Skip to content

Commit

Permalink
Merge pull request #1959 from ReviakinAleksey/fix_crudify_render_all
Browse files Browse the repository at this point in the history
Fix crudify render all

Template rendered for crud.all Snippet in net.liftweb.proto.Crudify renders
empty td elements instead of TheCrudType filed values.

This PR introduce issue fix and test for this functionality.
  • Loading branch information
Shadowfiend committed May 21, 2019
2 parents 975aa11 + eda694b commit 2fdb1ea
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 1 deletion.
3 changes: 3 additions & 0 deletions contributors.md 100644 → 100755
Expand Up @@ -281,3 +281,6 @@ Henrik Härkönen

### Email: ###
heharkon@iki.fi

### Email: ###
it dot blackdog at gmail dot com
2 changes: 1 addition & 1 deletion persistence/proto/src/main/scala/net/liftweb/proto/Crudify.scala 100644 → 100755
Expand Up @@ -644,7 +644,7 @@ trait Crudify {
pointer <- fieldsForList
field <- computeFieldFromPointer(c, pointer).toList
} yield {
".value *" #> field.asHtml
".row-item *" #> field.asHtml
}
}
}
Expand Down
110 changes: 110 additions & 0 deletions persistence/proto/src/test/scala/net/liftweb/CrudifySpec.scala
@@ -0,0 +1,110 @@
package net.liftweb

import net.liftweb.common.{Box, Full}
import net.liftweb.fixtures._
import net.liftweb.http.{Req, S}
import net.liftweb.proto.Crudify
import net.liftweb.util.{BaseField, FieldError, LiftValue}
import org.specs2.matcher.XmlMatchers
import org.specs2.mutable.Specification
import org.specs2.specification.Scope

import scala.xml.{NodeSeq, Text}

object CrudifySpec extends Specification with XmlMatchers {
"Crudify Trait Specification".title

/** Spec class implementation of [[net.liftweb.proto.Crudify]] trait */
trait SpecCrudify extends Crudify {

def repo: SpecCrudRepo

override type TheCrudType = SpecCrudType

override type FieldPointerType = SpecCrudType.FieldType


override def calcPrefix: List[String] = List("Prefix")

override def create: SpecCrudType = new SpecCrudType("", "")

override def fieldsForDisplay: List[FieldPointerType] = SpecCrudType.FIELDS

override def findForList(start: Long, count: Int): List[TheCrudType] = repo.all

override def findForParam(in: String): Box[TheCrudType] = repo.find(in)


override protected implicit def buildBridge(from: TheCrudType): CrudBridge = new CrudBridge {

override def delete_! : Boolean = repo.delete_!(from)


override def save: Boolean = repo.save(from)

override def validate: List[FieldError] = repo.validate(from)


override def primaryKeyFieldAsString: String = repo.primaryKeyFieldAsString(from)
}

override protected implicit def buildFieldBridge(from: FieldPointerType): FieldPointerBridge = new FieldPointerBridge {
override def displayHtml: NodeSeq = from.displayHtml
}

override protected def computeFieldFromPointer(instance: TheCrudType, pointer: FieldPointerType): Box[BaseField] = {
val result: BaseField = new BaseField with LiftValue[String] {
override def setFilter: List[String => String] = Nil

override def validations: List[String => List[FieldError]] = Nil

override def validate: List[FieldError] = Nil

override def toForm: Box[NodeSeq] = Full(Text(get))

override def name: String = pointer.fieldName

override def set(in: String): String = {
pointer.setter(instance, in)
in
}

override def get: String = pointer.getter(instance)
}
Full(result)
}
}

"Crudify `showAllTemplate`" should {

class SpecCrudifyWithContext extends SpecCrudify with Scope {
val repo: SpecCrudRepo = SpecCrudType.defaultRepo

def all: NodeSeq = S.statelessInit(Req.nil)({
doCrudAll(this.showAllTemplate())
})

}

"render proper rows count" in new SpecCrudifyWithContext {
all \\ "tbody" \\ "tr" must have size repo.size
}

"render proper headers content" in new SpecCrudifyWithContext {
val th: NodeSeq = all \\ "thead" \\ "th"
val renderedHeaders = th.map(_.text).filterNot(_ == "&nbsp;")
renderedHeaders must contain(exactly(SpecCrudType.FIELDS.map(_.fieldName): _*))
}

"render proper colums content" in new SpecCrudifyWithContext {
val tr: NodeSeq = all \\ "tbody" \\ "tr"
val renderedValues: List[List[String]] = tr.map(row => {
(row \ "td")
.filter(td => (td \ "@class").nonEmpty)
.map(_.text).toList
}).toList
val expectedValues: List[List[String]] = repo.all.map(i => List(i.id, i.value))
renderedValues === expectedValues
}
}
}
@@ -0,0 +1,97 @@
package net.liftweb
package fixtures

import net.liftweb.common.Box
import net.liftweb.util.FieldError

import scala.collection.mutable
import scala.xml.{NodeSeq, Text}

/**
* Helper type represents content for [[net.liftweb.proto.Crudify]]
*
* @param id fake data `id` field
* @param value fake data `value` field
*/
class SpecCrudType(var id: String, var value: String)

/** Helper object for [[net.liftweb.proto.Crudify]] trait testing */
object SpecCrudType {
/** [[net.liftweb.proto.Crudify.FieldPointerType]] */
type FieldType = SpecField[SpecCrudType]

/** Default initial [[SpecCrudRepo]] content */
val DEFAULT_REPO_CONTENT = List("1" -> new SpecCrudType("1", "first"),
"2" -> new SpecCrudType("2", "second"),
"3" -> new SpecCrudType("3", "third"))

/** Default fields for [[SpecCrudType]] */
val FIELDS: List[FieldType] = List(
SpecField("id", _.id, (h, v) => h.id = v),
SpecField("value", _.value, (h, v) => h.value = v))

/** Build [[SpecCrudRepo]] with default content */
def defaultRepo: SpecCrudRepo = new SpecCrudRepo(DEFAULT_REPO_CONTENT: _*)
}

/**
* Helper type witch should be used as [[net.liftweb.proto.Crudify.FieldPointerType]]
*
* @param fieldName fake date field na,e
* @param getter return `fieldName` value as [[String]] from [[T]] instance
* @param setter convert given [[String]] and it as set `fieldName` value in [[T]] instance
* @tparam T target fake data holder type ([[SpecCrudType]] for now)
*/
case class SpecField[T](fieldName: String, getter: T => String, setter: (T, String) => Unit) {

/**
* Field name as HTML
*
* @return Element with represents field name in HTML
*/
def displayHtml: NodeSeq = Text(fieldName)
}


/**
* Helper class for creating fake data repository for using as [[net.liftweb.proto.Crudify.CrudBridge]] and for others
* methods needed by [[net.liftweb.proto.Crudify]] implementation
*
* @param initalContent initial content for repor
*/
class SpecCrudRepo(initalContent: (String, SpecCrudType)*) {
private val dict: mutable.Map[String, SpecCrudType] = mutable.LinkedHashMap(initalContent: _*)

/** Return items count in repo */
def size: Int = dict.size

/** Return repo content */
//TODO: support for pagination
def all: List[SpecCrudType] = dict.values.toList

/** Find content in repo by [[String]] `id` param */
def find(id: String): Box[SpecCrudType] = {
dict.get(id)
}

/** Delete content from repo */
def delete_!(target: SpecCrudType): Boolean = {
dict.remove(target.id).isDefined
}

/** Save new instance to repo or replcace previous value inside repo if present */
def save(target: SpecCrudType): Boolean = {
dict += target.id -> target
true
}

/** Validate instance */
def validate(target: SpecCrudType): List[FieldError] = Nil


/** Return [[String]] representation of instance primary field */
def primaryKeyFieldAsString(target: SpecCrudType): String = target.id
}



0 comments on commit 2fdb1ea

Please sign in to comment.