Unable to run grails test-app :cucumber - testing

So I've looked through other peoples problems but they dont match what I'm seeing so thought I'd post it up to see if anyone else has had this issue and has a suggested solution
Im running a grails app in 2.3.5 and have cucumber 1.2.0
I've set up a really basic feature file in the functional folder that reads as follows: -
Feature:
As a user
If I enter the incorrect password I need a warning message
So I know i did something wrong
Scenario:
Given I enter the wrong login credentials
When I click sign in
Then Display a login error
Now I know this shouldn't work as yet but Im going one step at a time to see the process as Im new to cucumber and grails.
The app runs fine if I use the command
grails run-app -Dgrails.server.port.http=8090
If I then try running the cucumber test via
grails test-app :cucumber (with or without the port specification above) I get the following explosion...
Configuring Shiro ...
Shiro Configured
| Error 2017-03-15 08:28:35,222 [localhost-startStop-1] ERROR context.GrailsContextLoader - Error initializing the application: null
Message: null
Line | Method
->> 2076 | contains in java.lang.String
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 207 | canAutoMigrate in grails.plugin.databasemigration.MigrationUtils
| 43 | autoRun . . . in grails.plugin.databasemigration.MigrationRunner
| 87 | doCall in DatabaseMigrationGrailsPlugin$_closure2
| 262 | run . . . . . in java.util.concurrent.FutureTask
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
| Error 2017-03-15 08:28:35,247 [localhost-startStop-1] ERROR context.GrailsContextLoader - Error initializing Grails: null
Message: null
Line | Method
->> 2076 | contains in java.lang.String
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 207 | canAutoMigrate in grails.plugin.databasemigration.MigrationUtils
| 43 | autoRun . . . in grails.plugin.databasemigration.MigrationRunner
| 87 | doCall in DatabaseMigrationGrailsPlugin$_closure2
| 262 | run . . . . . in java.util.concurrent.FutureTask
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
| Error 2017-03-15 08:28:35,251 [localhost-startStop-1] ERROR [localhost].[/test] - Exception sending context initialized event to listener instance of class org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener
Message: Error executing bootstraps; nested exception is java.lang.NullPointerException
Line | Method
->> 262 | run in java.util.concurrent.FutureTask
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
Caused by NullPointerException: null
->> 2076 | contains in java.lang.String
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 207 | canAutoMigrate in grails.plugin.databasemigration.MigrationUtils
| 43 | autoRun . in grails.plugin.databasemigration.MigrationRunner
| 87 | doCall in DatabaseMigrationGrailsPlugin$_closure2
| 262 | run . . . in java.util.concurrent.FutureTask
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
| Error 2017-03-15 08:28:35,271 [localhost-startStop-1] ERROR core.StandardContext - Error listenerStart
| Error 2017-03-15 08:28:35,280 [localhost-startStop-1] ERROR core.StandardContext - Context [/myProject] startup failed due to previous errors
| Server running. Browse to http://localhost:8080/myProject
| Server stopped
| Error Fatal error running tests: No WebApplicationContext found: no ContextLoaderListener registered? (Use --stacktrace to see the full trace)
| Tests FAILED - view reports in /Users/me/Projects/myProject/target/test-reports
| Error Error executing script TestApp: java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered? (Use --stacktrace to see the full trace)
I have 0 idea what any of this means and googling any of it with a grails/cucumber context doesnt seem to really bring anything of sense back, any suggestions or questions welcome!
This is the content of my bootstrap.groovy file if that makes things any clearer, intellij doesn't register anything in here as broken just a few variables not being used...
import org.apache.shiro.crypto.hash.Sha256Hash
import uk.co.test.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
class BootStrap {
def queueService
def init = { servletContext ->
def adminRole = new ShiroRole(name: "admin")
adminRole.addToPermissions("admin:*:*")
adminRole.save()
def userRole = new ShiroRole(name: "user")
userRole.addToPermissions("application:*:*")
userRole.addToPermissions("assertion:*:*")
userRole.addToPermissions("auth:*:*")
userRole.addToPermissions("displayResult:*:*")
userRole.addToPermissions("event:*:*")
userRole.addToPermissions("executor:*:*")
userRole.addToPermissions("folderNode:*:*")
userRole.addToPermissions("form:*:*")
userRole.addToPermissions("interaction:*:*")
userRole.addToPermissions("manualTest:*:*")
userRole.addToPermissions("object:*:*")
userRole.addToPermissions("objectType:*:*")
userRole.addToPermissions("page:*:*")
userRole.addToPermissions("project:*:*")
userRole.addToPermissions("queue:*:*")
userRole.addToPermissions("release:*:*")
userRole.addToPermissions("result:*:*")
userRole.addToPermissions("test:*:*")
userRole.addToPermissions("testSet:*:*")
userRole.addToPermissions("user:*:*")
userRole.save()
def adminUser = new ShiroUser(username: "admin", passwordHash: new Sha256Hash("test").toHex())
adminUser.addToRoles(adminRole)
adminUser.addToRoles(userRole)
adminUser.save()
def nonAdminUser = new ShiroUser(username: "user", passwordHash: new Sha256Hash("test").toHex())
nonAdminUser.addToRoles(userRole)
nonAdminUser.save()
if (Interaction.list().size() == 0) {
def interaction = new Interaction('click')
interaction.save(failOnError: true)
interaction = new Interaction(name: 'check text', alias: 'checkText')
interaction.save(failOnError: true)
interaction = new Interaction(name: 'get attribute', alias: 'getAttribute')
interaction.save(failOnError: true)
interaction = new Interaction(name: 'enter text', alias: 'type')
interaction.save(failOnError: true)
interaction = new Interaction('select radio button')
interaction.save(failOnError: true)
interaction = new Interaction('select')
interaction.save(failOnError: true)
interaction = new Interaction('hover')
interaction.save(failOnError: true)
}
if (ObjectType.findAll().size() == 0) {
def firstType = new ObjectType(type: "button", typeSysCode: "BUTTON")
firstType.save()
def secondType = new ObjectType(type: "link", typeSysCode: "LINK")
secondType.save()
def thirdType = new ObjectType(type: "label", typeSysCode: "LABEL")
thirdType.save()
def fourthType = new ObjectType(type: "textbox", typeSysCode: "TEXTBOX")
fourthType.save()
}
if (Queue.list().size() == 0) {
def manualQueue = new Queue(name: "manual",
allowedTestTypes: [TestTypes.MANUAL.getValue()]
)
manualQueue.save(failOnError: true)
}
def sd = Executors.newSingleThreadScheduledExecutor()
sd.scheduleAtFixedRate(new QueueRunnable(), 10, 5, TimeUnit.SECONDS)
environments {
development {
def firstRelease
def secondRelease
if (Release.findAll().size() == 0) {
def firstProject
def secondProject
if (Project.findAll().size() == 0) {
firstProject = new Project(name: "d2c application")
firstProject.save(failOnError: true)
secondProject = new Project(name: "b2b application")
secondProject.save(failOnError: true)
} else {
firstProject = Project.findByName("d2c application")
secondProject = Project.findByName("b2b application")
}
if (Release.findAll().size() == 0) {
firstRelease = new Release(name: "d2c 1", project: firstProject)
firstRelease.save()
secondRelease = new Release(name: "d2c 2", parentRelease: Release.findByNameAndProject('d2c 1', firstProject), project: firstProject)
secondRelease.save()
def thirdRelease = new Release(name: "b2b 1", project: secondProject)
thirdRelease.save()
def fourthRelease = new Release(name: "b2b 2", parentRelease: Release.findByNameAndProject('b2b 1', secondProject), project: secondProject)
fourthRelease.save()
}
} else {
firstRelease = Release.get(1)
secondRelease = Release.get(2)
}
if (Object.findAll().size() == 0 && Page.findAll().size() == 0) {
def firstObject = new Object(name: "BBC welcome text",
idType: "css",
locatorValue: "h2.hp-banner__text",
type: ObjectType.get(2),
release: firstRelease,
objectVersion: 1,
objectNumber: 1,
interaction: Interaction.findByName('check text')
)
firstObject.save(failOnError: true)
def secondObject = new Object(name: "BBC news link",
idType: "css",
locatorValue: "li.orb-nav-news a",
type: ObjectType.get(1),
release: firstRelease,
objectVersion: 1,
objectNumber: 2,
interaction: Interaction.findByName('click')
)
secondObject.save(failOnError: true)
def thirdObject = new Object(name: "BBC news business link",
idType: "id",
locatorValue: "linky",
type: ObjectType.get(2),
release: firstRelease,
objectVersion: 1,
objectNumber: 3,
interaction: Interaction.findByName('click')
)
thirdObject.save(failOnError: true)
def firstPage = new Page(name: "BBC home",
pageNumber: 1,
pageVersion: 1,
release: firstRelease
)
firstPage.save(failOnError: true)
def secondPage = new Page(name: "BBC news",
pageNumber: 2,
pageVersion: 1,
release: firstRelease
)
secondPage.save(failOnError: true)
def firstPageObject = new PageObject(object: firstObject,
objectNumber: firstObject.objectNumber,
page: firstPage,
behaviour: "interact",
value: "Welcome to the BBC"
)
firstPageObject.save(failOnError: true)
def secondPageObject = new PageObject(object: secondObject,
objectNumber: secondObject.objectNumber,
page: firstPage,
behaviour: "interact"
)
secondPageObject.save(failOnError: true)
def thirdPageObject = new PageObject(object: thirdObject,
objectNumber: thirdObject.objectNumber,
page: secondPage,
behaviour: "interact"
)
thirdPageObject.save(failOnError: true)
firstPage.objects = [firstPageObject, secondPageObject]
firstPage.save(failOnError: true)
secondPage.objects = [thirdPageObject]
secondPage.save(failOnError: true)
}
}
}
}
def destroy = {
}
}

Related

Issues observed in " karate-junit5 " library when migrated from version 1.2.0 to 1.3.1

Recently I upgraded the version of karate-junit5 library from 1.2.0 to 1.3.1.
I have a common feature file which contains some common functions used all other scenarios like below sample.
common.feature
#Common
Scenario: Common scenario
* def someFunction =
"""
function(){
karate.log('In some function..');
var textArray = driver.locateAll("//*[#role='button']").map( x => x.text)
karate.log('Button text is: ', textArray);
}
"""
* def getDateInFormat =
"""
function(date){
var curr_date = date.getDate();
if(curr_date < 10)
curr_date = '0' + curr_date;
var curr_month = date.getMonth() + 1;
if(curr_month < 10)
curr_month = '0' + curr_month;
var curr_year = date.getFullYear();
var mod_date = curr_date + '/' + curr_month + '/' + curr_year;
return mod_date;
}
"""
* def sortFunction =
"""
function(sortArr, sortType){
if(sortType == 'asc')
sortArr.sort();
else
sortArr.reverse();
return sortArr;
}
"""
I call above common scenarios from other feature files whenever required. A sample calling feature file would be as below.
Test.feature
Feature: Test feature
Background:
* callonce read('common.feature#Common')
Scenario: Test 1
* print "Today's date is: ", getDateInFormat(new Date())
Scenario: Test 2
* print "Sorted data by A to Z is: ", sortFunction(['Dog', 'Cat', 'Horse'], 'asc')
Scenario: Test 3
* configure driver = { type: 'chrome', addOptions: ['--ignore-certificate-errors', '--incognito', '--disable-gpu', '--window-size=1920,1080', '--no-sandbox'], headless: false }
* configure retry = { count: 10, interval: 2000 }
* driver 'https://www.google.com/'
* someFunction()
All the scenarios 1,2 and 3 are executed properly for 1.2.0 version but throw below errors for when library version is upgraded to 1.3.1 :
For Scenario 1:
" org.graalvm.polyglot.PolyglotException: TypeError: invokeMember (getDate) on java.util.LinkedHashMap#6a969fb8 failed due to: Unknown identifier: getDate "
For Scenario 2:
" org.graalvm.polyglot.PolyglotException: TypeError: invokeMember (sort) on java.util.ArrayList#ff6077 failed due to: Arity error - expected: 1 actual: 0 "
For Scenario 3:
" org.graalvm.polyglot.PolyglotException: ReferenceError: "driver" is not defined "
Can somebody explain what has changed in karate-junit5 library version 1.3.1 from 1.2.0 ?
For Scenario 2, sortArr.reverse() is working properly even in 1.3.1 karate version. Above error is observed for sortArr.sort().
For Scenario 3, if I change the someFunction() to accept driver , like someFunction(driver), then it is executed properly on 1.3.1 version as well.

istanbul generates empty report

I wanted to launch istanbul in my project, however no matter what I do reports shows only zeros. like below :
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 0 | 0 | 0 | 0 |
----------|---------|----------|---------|---------|-------------------
Even though it shows above the coverage report list of the test that passed. For simplicity I created super simple project for replication where I have only one function in indentity.js file :
export const identity = (x) => x;
and one simple test licated in test.js file
import { identity } from "./identity.js";
import assert from "assert";
describe("identity", function () {
it("should return passed argument", () => {
assert.equal(identity(1), 1);
assert.equal(identity("string"), "string");
assert.deepEqual(identity({ a: 1 }), { a: 1 });
});
});
and after I run nyc mocha I expect to see 100% coverage but what I have is the same table with zeros.
Is there some settings I missed to see proper coverage report ?
Thx in advance.

Support passing from Scenario Outline to JSON file

I am going to reuse some features and calling multiple features in a Scenario Outline.
Since the features being called are common, we would like to define its parameters in its own parameter file, while the parameter values are defined in placeholder.
We hope the placeholder can get the value from the Outline Examples.
How to make it?
Feature: verify parameter passing
Scenario Outline: verify 2 calls
* def result1 = call read('baseFeature1.feature')
* def result2 = call read('baseFeature2.feature') result1
* print result2
Examples:
| fooValue |
| value1 |
| value2 |
Feature: feature to verify the parameter passing, no input parameter
Scenario: feature 1
Given def payload = read('classpath:feature_1.json')
* print 'feature 1' + payload
Given def result = { "barValue": "barValue"}
Feature: feature to verify the parameter passing, with input parameter from last step
Scenario: feature 2
Given def payload = read('classpath:feature_2.json')
* print payload
feature_1.json
{
"foo": "#(fooValue)"
}
feature_2.json
{
"foo": "fooValue",
"bar": "#(result1.barValue)"
}
I think the version currently in development will make this possible. Can you take a look at this GitHub issue and see if this addresses your question: https://github.com/intuit/karate/issues/717
It will also be great if you can build from source and try this new capability.
Scenario Outline: magic variables with embedded expressions
* def expected = __num == 0 ? { name: 'Bob', alive: false } : { name: 'Nyan', alive: true }
* match expected == { name: '#(__row.name)', alive: '#(__row.alive)' }
* eval karate.set(__row)
# you can read from a re-usable JSON file instead of the line below
* match expected == { name: '#(name)', alive: '#(alive)' }
Examples:
| name | alive! |
| Bob | false |
| Nyan | true |

Using karate-config parameters in a feature file

The karate header examples do not show how to access config values other than baseUrl. When I switch environments (passing in -Dkarate.env=qual as part of the run command) then baseUrl is set correctly.
The problem is, I want to use other config values as shown here but when I run the test, it fails to access config.ApiKey correctly. Instead I get this error
html report:
file:/C:/bitbucket/karate-checkdigit-api/target/surefire-reports/TEST-features.checkdigitapi.VA.html
Tests run: 250, Failures: 0, Errors: 50, Skipped: 175, Time elapsed: 4.112 sec <<< FAILURE!
* def secretKey = config.apiKey(| XYZ | 2110974841 | 204 | Valid |) Time elapsed: 0.005 sec <<< ERROR!
java.lang.RuntimeException: no variable found with name: config
at com.intuit.karate.Script.getValuebyName(Script.java:323)
at com.intuit.karate.Script.evalJsonPathOnVarByName(Script.java:378)
at com.intuit.karate.Script.eval(Script.java:309)
at com.intuit.karate.Script.eval(Script.java:194)
at com.intuit.karate.Script.assign(Script.java:656)
at com.intuit.karate.Script.assign(Script.java:587)
at com.intuit.karate.StepDefs.def(StepDefs.java:265)
at ✽.* def secretKey = config.apiKey(features/checkdigitapi/XYZ.feature:6)
My .feature file and karate-config.js are below.
XYZ.feature
#regression
Feature: Checkdigit Algorithm API
Background:
* url baseUrl
* def secretKey = config.apiKey
* configure ssl = true
Scenario Outline: Testing XYZ algorithm
* configure headers = { KeyId: secretKey, Accept: 'application/json' }
Given path 'headers'
And param url = baseUrl
And params { customerId: '<custcode>', algoId: '<algo>' }
When method get
Then status <val>
Examples:
| algo | custcode | val | comment |
| XYZ | 2110974841 | 204 | Valid |
| XYZ | 7790011614 | 204 | Valid |
| XYZ | 5580015174 | 204 | Valid |
| XYZ | 2110974840 | 400 | expected check digit 1 |
| XYZ | 211097484 | 400 | not 10 digits |
| XYZ | 211097484x | 400 | not numeric |
karate-config.js
function() {
//set up runtime variables based on environment
//get system property 'karate.env'
var env = karate.env;
if (!env) { env = 'dev'; } // default when karate.env not set
// base config
var config = {
env: env,
baseUrl: 'https://localapi.abc123.example.com/api/v1/validate/customerid',
apiKey: ''
}
//switch environment
if (env == 'dev') {
config.baseUrl = 'https://devapi.abc123.example.com/api/v1/validate/customerid';
config.apiKey = 'fake-1ba403ca8938176f3a62de6d30cfb8e';
}
else if (env == 'qual') { //Pre-production environment settings
config.baseUrl = 'https://qualapi.abc123.example.com/api/v1/validate/customerid';
config.apiKey = 'fake-d5de2eb8c0920537f5488f6535c139f2';
}
karate.log('karate.env =', karate.env);
karate.log('config.baseUrl =', config.baseUrl);
karate.log('config.apiKey =', config.apiKey);
return config;
}
(similar issue here, using a separate headers.js: https://github.com/intuit/karate/issues/94)
Keep in mind that all the keys within the JSON object returned by karate-config.js will be injected as variables, and nothing else. So you will not be able to refer to config, but you will certainly be able to refer to apiKey.
I think if you make this simple change, things will start working:
* def secretKey = apiKey
Also, I think you have a problem in the first line of the scenario, it should be:
* configure headers = { KeyId: '#(secretKey)', Accept: 'application/json' }
FYI my final, correctly working XYZ.feature file looks like this now.
The line Given path 'headers' caused header info to creep into the url so it's removed.
XYZ.feature
#regression
Feature: Checkdigit Algorithm API
Background:
* url baseUrl
* def secretKey = apiKey
* configure ssl = true
Scenario Outline: Testing XYZ algorithm
* configure headers = { KeyId: '#(secretKey)', Accept: 'application/json' }
Given url baseUrl
And params { customerId: '<custcode>', algoId: '<algo>' }
When method get
Then status <val>
Examples:
[...]

GORM (varchar .save(), non DATE): ORA-01861: literal does not match format string

Hello I'm receiving a very strange error: ORA-01861: literal does not match format string. All my internet searching has related to DATE issues. Mine is just to save a simple string. If you see the issue please let me know how to fix it.
Column of issue
TREND: VARCHAR2(31, CHAR), no constraints
Mapped in GORM by:
String trend
...
static constraints = {
trend(nullable: true, blank: true)
... } ...
static mapping = {
trend column: "TREND", sqlType: "varchar(31)"
...}
Issue method:
def fix_trend(){
// There should ever only be three values found in the trend column
// of the Reports table: "TRENDING UP", "TRENDING STEADY", "TRENDING DOWN"
println "Running groovy database procedure : fix_trend"
StatusReport.list().each{
String trend = it.trend
if (trend != 'TRENDING UP' && trend != 'TRENDING STEADY' && trend != 'TRENDING DOWN'){
trend = trend?.toUpperCase()
if (trend == null){
trend = 'TRENDING STEADY'
}
else if (trend.contains('UP')){
trend = 'TRENDING UP';
}
else if (trend.contains('DOWN')){
trend = 'TRENDING DOWN';
}
else{
trend = 'TRENDING STEADY';
}
it.trend = trend;
it.save();
}
}
println "fix_trend completed"
}
The purpose of the method is to ensure all the values are either TRENDING UP, TRENDING DOWN, or TRENDING STEADY.
Stacktrace:
Running groovy database procedure : fix_trend
fix_trend completed
Error |
2015-01-05 10:53:02,392 [http-bio-8080-exec-4] ERROR spi.SqlExceptionHelper - ORA-01861: literal does not match format string
Error |
2015-01-05 10:53:02,481 [http-bio-8080-exec-4] ERROR errors.GrailsExceptionResolver - SQLDataException occurred when processing request: [GET] /investigator/statusReports/selection
ORA-01861: literal does not match format string
. Stacktrace follows:
Message: ORA-01861: literal does not match format string
Line | Method
->> 439 | processError in oracle.jdbc.driver.T4CTTIoer
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 395 | processError in ''
| 802 | processError . . . . in oracle.jdbc.driver.T4C8Oall
| 436 | receive in oracle.jdbc.driver.T4CTTIfun
| 186 | doRPC . . . . . . . in ''
| 521 | doOALL in oracle.jdbc.driver.T4C8Oall
| 205 | doOall8 . . . . . . in oracle.jdbc.driver.T4CPreparedStatement
| 1008 | executeForRows in ''
| 1307 | doExecuteWithTimeout in oracle.jdbc.driver.OracleStatement
| 3449 | executeInternal in oracle.jdbc.driver.OraclePreparedStatement
| 3530 | executeUpdate . . . in ''
| 1350 | executeUpdate in oracle.jdbc.driver.OraclePreparedStatementWrapper
| 16 | selection . . . . . in investigator.StatusReportsController
| 198 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter . . . . . . in grails.plugin.cache.web.filter.AbstractFilter
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
I solved my own issue.
There was a Date field in the table that was misrepresented as a String in the Domain class. Even though I was trying to update a VARCHAR2 field the domain_class.save() method updates every attribute of that domain_class-- thus the error was not associated with the TREND field but the misrepresented DATE field.
I figured this out by adding to DataSource.groovy
logSql = true
formatSql = true
and Config.groovy
log4j.main = {
trace 'org.hibernate.type'
debug 'org.hibernate.SQL'
...
This showed that the update statement generated by .save() tries to update EVERY attribute.
Hope this helps someone in the future.