I'm attempting to create a geb module that represents an unordered list of elements. I've seen examples for how to do this with tables but I'm having a hard time translating that to UL->LI elements. Here's what I have so far:
class CheckoutPage extends Page {
static content = {
cartItemList { $(".cart_items ul") }
cartItem { i -> module CartItem, cartItems[i] }
cartItems(required: false) { cartItemList.find("li.item") }
}
}
class CartItem extends Module {
static content = {
thumbnail { $("img.book_cover", it) }
itemInfo { $("div.item_info", it) }
bookTitle { itemInfo.find("h1").find("a").text() }
}
}
When I do the following in my spec:
def "add an item to the cart"() {
when:
to CheckoutPage, productId: "10001"
then:
cartItems.size() == 1
def cartItem = cartItems(0)
cartItem.bookTitle == "Test Book Title 001"
}
I get the following error:
geb.error.UnresolvablePropertyException: Unable to resolve bookTitle
as content for cartItems
However, cartItem is a DOM element because I can do this and it works:
cartItem.find("div.item_info").find("h1").find("a").text() == "Test Book Title 001"
You may want to check out this blog post. It outlines almost exactly what you're looking for.
http://adhockery.blogspot.com/2010/11/modelling-repeating-structures-with-geb.html
After looking through that blog post, this is what I came up with for your page class:
class CheckoutPage extends Page {
static content = {
cartItemList { $(".cart_items ul") }
cartItems(required: false) {
cartItemList.find("li.item").collect { item->
module(CartItem, item)
}
}
}
}
Then your module should look like this:
class CartItem extends Module {
static content = {
thumbnail { $("img.book_cover") }
itemInfo { $("div.item_info") }
bookTitle { itemInfo.find("h1").find("a").text() }
}
}
It looks like you have a bug in your code - you probably wanted to say def cartItem = cartItem(0) not def cartItem = cartItems(0). Also, try to avoid using the same names for local variables and your content definitions (like you do for cartItem) as it sometimes leads to name clashes which are pretty hard to track down.
You could simplify your content definition by using moduleList() method
static content = {
cartItemList { $(".cart_items ul") }
cartItems { i -> moduleList CartItem, cartItemList.find("li.item"), i }
}
and in your test:
then:
cartItems.size() == 1 //here you use it to retrieve the full list
def item = cartItems(0) //here you use it to retrieve a single element
item.bookTitle == "Test Book Title 001"
The answer to this question was a combination of both answers given. I needed those answers to better understand what was happening. This is the actual solution:
class CheckoutPage extends Page {
static content = {
cartItemList { $(".cart_items ul") }
cartItems(required: false) { module CartItem, cartItemList.find("li.item")}
}
}
class CartItem extends Module {
static content = {
thumbnail { $("img.book_cover") }
itemInfo { $("div.item_info") }
bookTitle { itemInfo.find("h1").find("a").text() }
}
}
And the test:
def "add an item to the cart"() {
when:
to CheckoutPage, productId: '10001'
then:
cartItems.size() == 1
def cartItem = cartItems(0)
cartItem.bookTitle == "Test Book Title 001"
}
The reasons (I think) this works is because we're dealing with individual LI elements. Not a container like a TR with several TD elements. So the context here is the LI and by using module instead of moduleList, I am only dealing with the individual LI element, and not a list of them. The cartItems contains the LI elements as a List already.
At least, that is how I understand it and it is working.
Related
How to get the value as following codes with my show view page on Grails?
Person.groovy
package com
class Person {
String person
static constraints = {
person blank:false,nullable:true
}
static hasMany=[task:Task]
String toString(){return person}
static mapping={
}
}
Task.groovy
package com.moog
class Task {
String task
static constraints = {
task blank:false,nullable:true,unique:true
}
static belongsTo=[person:Person]
static hasMany=[tag:Tag]
String toString(){return task}
}
Tag.groovy
package com
class Tag {
String tag
static constraints = {
tag blank:false, nullable:true
}
static belongsTo=[task:Task]
String toString(){
return tag
}
}
First of all try a better wording for your collections
static hasMany=[tasks:Task] // in Person.groovy
static hasMany=[tags:Tag] // in Task.groovy
In your person show.gsp try something like
<g:each in=${person.tasks} var="task">
<p>${task}</p>
</g:each>
If you do not use scaffolding and write you own controller methods to create your entities than maybe this helps you further:
def task = new Task(task:"Clean room")
def person = Person.get(1)
person.addToTasks(task)
person.save()
I have the following domain objects:
class Blog {
String foo
}
class Comment {
String bar
}
class BlogComment {
Blog blog
Comment comment
}
So far I've written this:
def getComments(Blog blog) {
def blogCommentCriteria = BlogComment.createCriteria()
def blogCommentResults = blogCommentCriteria.list {
eq 'blog.id', blog.id
}
List<Comment> comments = new Vector<Blog>()
blogCommentResults.each { i ->
if(i.blog == blog) {
comments.add(i.comment)
}
}
comments
}
What would be the most efficient method? I want the method to be clean and simple, but also efficient in terms of time taken.
You can add a method to the Blog class to get the comments associated with a given blog:
class Blog {
String foo
def getComments() {
BlogComment.findAllByBlog(this)*.comment
}
}
I having a GSP when it is accessed by two or more user at same time, It will throw
Row was updated or deleted by another transaction
Is there any way to share the render safely
Note: There is no update or save operation while rendering
Dude ,Have you tired on the action who updates ,list and read or connected with the row can be
#Transactional or do some concurrencyStuff exception handling
//Assume your domains are implemented just like or to be like this
class Author {
String name
Integer age
static hasMany = [books: Book]
}
//option one in your controllers or service class
Author.withTransaction { status ->
new Author(name: "Stephen King", age: 40).save()
status.setRollbackOnly()
}
Author.withTransaction { status ->
new Author(name: "Stephen King", age: 40).save()
}
//or
#Transactionl
def AuthorController () {
[list:list]
}
//or define a service like this
import org.springframework.transaction.annotation.Transactional
class BookService {
#Transactional(readOnly = true)
def listBooks() {
Book.list()
}
#Transactional
def updateBook() {
// …
}
def deleteBook() {
// …
}
}
for more visit : I hope this will be a bit useful ,Buddy!
My (simplified) domain model looks like this:
class Student {
static hasMany = [professions:StudentProfession];
}
class StudentProfession {
static belongsTo = [student:Student];
Profession profession;
}
class Profession {
String name;
}
What is the most efficient way to:
List all students that are taught "Programmer" and "Manager" professions
Am I forced to filter them out after querying the database?
students = students.findAll { student ->
student.professions.find { professionNames.contains(it.profession.name) } != null
}
You can do this using a GORM query:
def studends = Student.where {
professions {
profession.name == "Programmer" || profession.name == "Manager"
}
}
Lots of ways to skin this cat - here's one:
StudentProfession.findAllByProfessionInList(Profession.findAllByNameInList(["Programmer","Manager"])*.student.unique()
earlier I use Spring MVC and annotation #ModelAttribute.
#Controller
public class ArticleController {
#ModelAttribute("articles")
public List<Testset> getArticles(){
return articleDao.all();
}
#RequestMapping("/first.htm")
public void first(){
}
}
How can made this behaviour in Grails controller?
class ArticleController{
//this variable I want to in every action
List articles
def first = { }
def second = { }
def third = { }
}
Of course I can use this code for every action
def first = {
this.articles = Article.all()
}
but I want not this.
Thank very much for your help.
Tomáš
You can define an after interceptor and add data to the model there:
class ArticleController {
def afterInterceptor = { model ->
model.articles = Article.list()
}
def first = { }
def second = { }
def third = { }
}
The docs for this are here: http://grails.org/doc/latest/ref/Controllers/afterInterceptor.html