Grails and Geb: Reproducible deletion test - grails

I want to test a simple CRUD deletion with Geb, Grails and RemoteControl.
Here my simplified code:
test "Delete a book"() {
when:
to BookShowPage // book/show/1
deleteLink.click(BookListPage)
then:
// ...
cleanup:
def remote = new RemoteControl()
remote {
new Book(title:'title').save(failOnError: true, flush: true)
return true
}
}
But how can I make my test reproducible?
If I repeat my test, the new book will have another id and so test fails.

According to railsdog's comment, I resolved creating a new Book in the given block.
Here the right code:
test "Delete a book"() {
given:
def remote = new RemoteControl()
def bookId = remote {
Book book = new Book(title:'title').save(failOnError: true)
return book.id
}
when:
to BookShowPage, bookId // (*)
deleteLink.click(BookListPage)
then:
// ...
cleanup:
remote {
Book book = Book.get(bookId)
if (book) {
// Test fails and we have junk into the db...
book.delete(failOnError: true)
}
return true
}
}
(*) See how to customize Geb page URL.

Related

Want to Delete and Insert in same Action

I have one action in my controller that upload csv file with list of numbers.
Now the process is first I need to delete existing data from the table on certain condition then insert fresh data.
My snippet code is as follows..
Controller:
#Transactional
def uploadFile() {
if(!params?.updateExisting){
println "Going to call service to delete records"
myService.deleteNumbers()
def newList = Number.findAllByDeleted(false)
println "NEW LS:"+newList
//HERE I'm GETTING BLANK
}
def file = request.getFile("fileCsv")
file.inputStream
.splitEachLine(',') { fields ->
Number.withNewTransaction {
def number = fields[0]?.toString().replaceAll(" ","").replaceAll("-","")
Number numberInstance = new Number()
def numberExist = Number.findAllByNumberAndDeleted(number, false)
//HERE NUMBER IS STILL EXIST
if(!numberExist){
numberInstance.number = number
numberInstance.save(flush:true)
count++
}else{
println "Number exist: "+number
}
}
}
redirect(uri:'/number/list')
}
myService:
#Transactional
def deleteNumbers(){
Number.findAll().each {
it.deleted = true
it.save(flush: true)
}
}
After calling service method deleteNumbers I'm getting blank list NEW LS:[], But then def numberExist = Number.findAllByNumberAndDeleted(number, false) returns me a number means already exist.
Thanks..
Try removing Number.withNewTransaction closure. Your code should work..

Mock Grails configurations in Integration test cases

How to mock Grails configurations in Integration test cases?
Consider following scenario
MyController.groovy
def save() {
baseLink = Holders.getFlatConfig()["grails.test.base.link"]
if (!baseLink) {
response.status = HttpStatus.NOT_ACCEPTABLE.value
respond([message: "Configuration not found."])
return
}
// Some Code
}
MyControllerIntegrationSpec.groovy
def save() {
baseLink = Holders.getFlatConfig()["grails.test.base.link"]
if (!baseLink) {
response.status = HttpStatus.NOT_ACCEPTABLE.value
respond([message: "Configuration not found."])
return
}
// Some Code
}
def setup() {
//Some Setup Code
//Update configuration
grailsApplication.config["grails.test.base.link"] = true
}
void "Configuration not found"() {
when: ""
myController.save()
then: "Configuration not found"
controller.response.json["message"] == "Configuration not found."
controller.response.status == HttpStatus.NOT_ACCEPTABLE.value
}
void "Configuration found"() {
when: ""
myController.save()
then: "Configuration found"
//some code
}
Assuming you know why you want to mock the grails application in an integration test, my suggestion would be to use DI of grailsApplication. Is there any reason why you use baseLink = Holders.getFlatConfig()["grails.test.base.link"] instead of grailsApplication.config.grails.test.base.link ? What grails version are you using?
When using grailsApplication as a dependency the controller, you can inject it in the test:
def setup() {
myController.grailsApplication = [config: [grails: [test: [base: [link: true]]]]]
}
void "Configuration found"() {
when: ""
myController.save()
then: "Configuration found"
//some code
}

Grails integration test doesn't work in test-app but is running correctly when starting alone

I am testing a service-class which do a little gorm-action.
If i run the test alone as integration-test it runs without failures and if i run test-app (does not matter if i run test-app integration:) my test fails and i got the error message, that the used domain classes:
"Method on class [xx.xx.User] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly."
Since its an integration-test, i dont want to mock the domain-classes and i just dont understand this error. I am using grails 2.3.5 with the correct tomcat and hibernate plugin:
#TestFor(EntryService)
//#Mock([User, Task, Entry, Admin])
class EntryServiceSpec extends Specification {
Entry entry1
EntryService entryService
User user
Task task
Date date
def setup() {
entryService = new EntryService()
user = User.findByEmail("test#test.de")
task = Task.findByName("something_inserted")
date = new Date().clearTime()
entry1 = new Entry()
entry1.comment = ""
entry1.effort = 23 as BigDecimal
entry1.user = user
entry1.bookedTask = task
entry1.bookedCosts = 300 as BigDecimal
entry1.entryDay = new Date().clearTime()
entry1.save(flush: true)
}
def cleanup() {
if(entry1 != null && entry1.id != null) {
entry1.delete()
}
}
void "Wished effort that shall be added is exceeding 24-hours day-constraints"() {
expect: "user has 23h erfforts, wants to add 2 more hours, it should exceed"
entryService.isEntryEffortExceedingHoursConstraintsPerDay(user, date, new BigDecimal(2)) == true
}
void "Wished effort that shall be added is not exceeding 24-hours day-constraints"() {
expect: "user has 23h erfforts, wants to add 1 more hours, it should not exceed"
entryService.isEntryEffortExceedingHoursConstraintsPerDay(user, date, new BigDecimal(1)) == false
}
void "null parameter should leed to return false"() {
expect: "user is null, method should return false"
entryService.isEntryEffortExceedingHoursConstraintsPerDay(null, date, new BigDecimal(1)) == false
and: "date is null, method should return false"
entryService.isEntryEffortExceedingHoursConstraintsPerDay(user, null, new BigDecimal(1)) == false
and: "wished-effort is null, method should return false"
entryService.isEntryEffortExceedingHoursConstraintsPerDay(user, date, null) == false
}
}
Give credit to #dmahapatro who answered this in the comments above
You are running your test as a Unit test and not as a Integration test...
change you class signature to:
import grails.test.spock.IntegrationSpec
class EntryServiceSpec extends IntegrationSpec
notice that I also removed the #TestFor(EntryService)

grails webflow error

i have this grails webflow
def currencyDescriptionFlow = {
start {
action {
flow.messageCommand = new MessageCommand()
flow.currencyId = params.id
flow.languageList = Language.findAll([sort: 'codeDescription', order: 'asc'])
}
on('success').to('description')
}
description{
action{
flow.DescriptionMessageList = Message.findAllByKey(flow.currencyId + '_Currency')
}
on('add').to('addSubmit')
on('finish').to('currencyShow')
}
addSubmit{
action {
MessageCommand cmd ->
flow.messageCommand = cmd
if (!flow.messageCommand.validate()){
error()
}
}
on('error').to('description')
on('success').to('description')
}
saveMessage{
action{
def str = flow.currencyId + '_Currency'
messageSevice.descriptionMultiLanguage(str, params.description, params.Language)
}
on('error').to('description')
on('success').to('description')
}
currencyShow{
redirect(controller:'currency', action: "show", id: flow.currencyId)
}
}
when i click the link to redirect to this page, ann error occurs
Error 500: No transition was matched on the event(s) signaled by the [1] action(s)
that executed in this action state 'description' of flow 'message/currencyDescription';
transitions must be defined to handle action result outcomes -- possible flow
configuration error? Note: the eventIds signaled were: 'array<String>
['success']', while the supported set of transitional criteria for this action
state is 'array<TransitionCriteria>[add, finish]'
Servlet: grails
URI: /adm-appserver-manager/grails/message/currencyDescription.dispatch
Exception Message: No transition was matched on the event(s) signaled by the [1]
action(s) that executed in this action state 'description' of flow 'message/currencyDescription';
transitions must be defined to handle action result outcomes -- possible flow
configuration error? Note: the eventIds signaled were: 'array<String>
['success']', while the supported set of transitional criteria for this action state
is 'array<TransitionCriteria>[add, finish]'
Caused by: No transition was matched on the event(s) signaled by the [1] action(s)
that executed in this action state 'description' of flow 'message/currencyDescription';
transitions must be defined to handle action result outcomes -- possible flow
configuration error? Note: the eventIds signaled were: 'array<String>['success']',
while the supported set of transitional criteria for this action state is
'array<TransitionCriteria>[add, finish]'
Class: Unknown
At Line: [-1]
Code Snippet:
Note:
where language is a table in the database
MessageCommand is command object
messageService is a service
descriptionMultiLanguage method in message service for saving message
i try this way of writing code in another action and controoler and it works without any error.
by debugging this code i found the error on (
on('add').to('addSubmit')
on('finish').to('currencyShow')
)
when i remove these 2 lines , no problem found
def currencyDescriptionFlow = {
start {
action {
flow.messageCommand = new MessageCommand()
flow.currencyId = params.id
flow.languageList = Language.findAll([sort: 'codeDescription', order: 'asc'])
flow.DescriptionMessageList = Message.findAllByKey(flow.currencyId + '_Currency')
}
on('success').to('description')
}
description{
on('add').to('addSubmit')
on('finish').to('currencyShow')
}
addSubmit{
action {
MessageCommand cmd ->
flow.messageCommand = cmd
if (!flow.messageCommand.validate()){
error()
}
flow.message = null
}
on('error').to('description')
on('success').to('saveMessage')
}
saveMessage{
action{
Message messageInstance = new Message(language:flow.messageCommand.language,value:flow.messageCommand.value,key:flow.currencyId + '_Currency')
if (!messageInstance.save(flush:true)){
flow.message = "${message(code: 'error.adding.description')}"
error()
}
flow.DescriptionMessageList = Message.findAllByKey(flow.currencyId + '_Currency')
}
on('error').to('description')
on('success').to('description')
}
currencyShow{
redirect(controller:'currency', action: "show", id: flow.currencyId)
}
}

webflow in grails application

how can i redirect to the same state more than one time using web flow
ex:
on('submit'){
def destinationInstance = Destination.get(params.destination)
def destinationGroupsInstance = DestinationGroup.get(params.destinationGroups)
def h = destinationInstance.addToDestinationGroups(destinationGroupsInstance)
}.to('flowList')
what i need is how to enter to this state more than one time until destinations ends
thx
on('submit'){
def destinationInstance = Destination.get(params.destination)
def destinationGroupsInstance = DestinationGroup.get(params.destinationGroups)
def h = destinationInstance.addToDestinationGroups(destinationGroupsInstance)
}.to{
(condition or while loop or for loop)
if success then
return "<state name>"
else
return "flowList"
}
Reference:
http://livesnippets.cloudfoundry.com/docs/guide/2.%20Grails%20webflow%20plugin.html
Well, you'd probably have something like the following code, which is untested but may give you a general idea.
def destinationFlow = {
initialize {
action {
flow.destination = Destination.get(params.id)
}
on('success').to 'destinationList'
}
destinationList {
render(view: 'destinationList')
on('addDestination') {
def destinationGroup = DestinationGroup.get(params.destinationGroupId)
flow.destination.addToDestinationGroups(destinationGroup)
}.to 'destinationList'
on('finish').to 'done'
}
done {
flow.destination.save()
redirect(...) // out of the flow
}
}
You'll need buttons on your destinationList view that invoke the 'addDestination' or 'finish' actions. See the WebFlow documentation and Reference Guide.

Resources