-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
before week 3, initial Grails artefacts
- Loading branch information
Dierk Koenig
committed
Oct 3, 2023
1 parent
42a2c5e
commit 88a9047
Showing
15 changed files
with
417 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# WebEngineering Module, rooms | ||
|
||
## Goals | ||
|
||
### Abilities | ||
- Writing tests for page navigation | ||
- Writing tests for form submission | ||
- Implementing basic workflow: form - controller - view | ||
- Constructing html views with derived content | ||
- Validating appropriately | ||
|
||
### Knowledge | ||
- Understanding the purpose and benefit of functional tests on the web | ||
- Understanding the purpose and benefit of unit tests | ||
- Understanding the web rooms cycle, request-response paradigm | ||
- Using models for request data binding and response view creation | ||
- Where and how to validate | ||
|
||
## Assignment 1 | ||
|
||
Make sure that you have a Java JDK 17 installed and `JAVA_HOME` | ||
set appropriately. Check by running | ||
|
||
java -version | ||
|
||
Run the tests | ||
|
||
grailsw test-app | ||
|
||
_this will take a while to download the first time_ | ||
|
||
Run the application | ||
|
||
grailsw run-app | ||
|
||
Browse to http://localhost:8080/static/Home.html . | ||
|
||
## Assignment 2 | ||
|
||
Have a look at rooms/src/integration-test/groovy/rooms/HomeSecondSpec.groovy . | ||
|
||
Write a test, that goes to http://www.fhnw.ch/de/ | ||
and clicks on a link with text "Standorte und Kontakt". | ||
Validate the page title. | ||
|
||
## Assignment 3 | ||
|
||
Have a look at | ||
- http://localhost:8080/static/GradeCalculator.html | ||
- rooms/src/integration-test/groovy/rooms/CalculatorSpec.groovy (note the commented line 26) | ||
- rooms/src/main/resources/public/GradeCalculator.html | ||
- rooms/grails-app/controllers/rooms/CalculatorController.groovy | ||
- rooms/views/calculator/CalculatorOutput.gsp (note the output placeholder) | ||
- rooms/src/test/groovy/rooms/CalculatorControllerSpec.groovy | ||
|
||
Uncomment line 26 in the integration test and run `grailsw test-app`. | ||
|
||
Open `/build/reports/tests/index.html` (or look at the internal test runner) | ||
to see which test failed and why. | ||
|
||
Use `${ result }` in CalculatorOutput.gsp to put that calculated result in the right place. | ||
|
||
## Assignment 4 | ||
|
||
In the GradeCalculator: | ||
what happens when _en_ or _exam_ do not represent numbers? | ||
|
||
Extend the integration test to cover the invalid input scenario. | ||
|
||
## Assignment 5 | ||
|
||
What happens when _en_ or _exam_ do not fall into 1.0 - 6.0? | ||
|
||
Write down how you would address this issue. | ||
Unit test or integration test? | ||
Which code needs change: test, controller, view? | ||
|
||
|
||
## Homework | ||
|
||
Take the InPlaceCalculator and modify the current solution so that | ||
- when the "en" field does not validate, | ||
an error message is displayed right beneath the field and | ||
the en input field itself is marked with a red border | ||
- when the "exam" field does not validate, | ||
an error message is displayed right beneath the field and | ||
the exam input field itself is marked with a red border | ||
- note that both, en and exam, may be erroneous at the same time. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package rooms | ||
|
||
class CalculatorController { | ||
|
||
def calc(double en, double exam) { | ||
double result = (en + exam) / 2 | ||
render view: "CalculatorOutput", model: [result: result] | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
grails-app/controllers/rooms/InPlaceCalculatorController.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package rooms | ||
|
||
import grails.validation.Validateable | ||
|
||
class InPlaceCalculatorController { | ||
|
||
def calc(CalculatorModel calcModel) { | ||
calcModel.en = Math.round(calcModel.en * 10) / 10 | ||
calcModel.exam = Math.round(calcModel.exam * 10) / 10 | ||
calcModel.result = Math.round((calcModel.en + calcModel.exam) / 2) | ||
if (calcModel.hasErrors()) { | ||
calcModel.result = "Cannot calculate. Input data was invalid." | ||
} | ||
render view:'calc', model: [calculatorInstance: calcModel] | ||
} | ||
|
||
} | ||
|
||
class CalculatorModel implements Validateable { | ||
double en = 0.0 | ||
double exam = 0.0 | ||
String result = "" | ||
|
||
static constraints = { | ||
en min:1d, max:6d, scale:1 | ||
exam min:1d, max:6d, scale:1 | ||
result nullable:true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package rooms | ||
|
||
class DecorationTagLib { | ||
static defaultEncodeAs = 'raw' | ||
static namespace = "rooms" | ||
|
||
def decorate = { attributes, body -> | ||
String grade = attributes.grade | ||
def decor = "<img src='http://2.bp.blogspot.com/"; | ||
switch (grade) { | ||
case ["1","2","3"] : decor += "-rnfZUujszZI/UZEFYJ269-I/AAAAAAAADnw/BbB-v_QWo1w/s1600/facebook-frown-emoticon.png'>"; break | ||
case ["4","5","6"] : decor += "-qODY1kxipZ0/Tv5dwDFFntI/AAAAAAAAAjM/cLXT6KEp-bE/s400/sunglasses%2Bemoticon.png'>"; break | ||
default: decor = "" | ||
} | ||
out << decor | ||
out << body() | ||
out << decor | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package rooms | ||
|
||
import grails.validation.Validateable | ||
import org.springframework.validation.FieldError | ||
|
||
class FieldUtil { | ||
static boolean hasError(Validateable model, String propertyName) { | ||
null != findError(model, propertyName) | ||
} | ||
static FieldError findError(Validateable model, String propertyName) { | ||
model.errors.fieldErrors.find {it.field == propertyName} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<title> | ||
Average | ||
</title> | ||
</head> | ||
<body> | ||
|
||
<p> Your average is <output>placeholder goes here</output>.</p> | ||
|
||
<p> Back to the <a href="/static/GradeCalculator.html">calculator</a>.</p> | ||
|
||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<%-- | ||
Emitting a single row of a form with label an input field. | ||
Params: | ||
name : name to use for id, name, labelFor | ||
label : what the user sees beneath the input field | ||
model : the values to show and error information | ||
Depends on the "validate" function from outside. | ||
--%> | ||
|
||
<%@ page import="static rooms.FieldUtil.*" %> | ||
|
||
<div> | ||
<label for='${name}'>${label}</label> | ||
<input type="number decimal" name="${name}" value="${model.getProperty(name)}" | ||
required="true" min="1.0" max="6.0" id="${name}" | ||
class="${hasError(model, name) ? 'error' : ''}" | ||
title="${g.message(error: findError(model, name)) }" | ||
|
||
/> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta name="layout" content="form"/> | ||
<title> | ||
In-Place Calculator | ||
</title> | ||
</head> | ||
|
||
<body> | ||
|
||
<form action="/inPlaceCalculator/calc" method="get"> | ||
<fieldset class="form padded"> | ||
|
||
<tmpl:form_row name="en" label="En" model="${calculatorInstance}" /> | ||
|
||
<tmpl:form_row name="exam" label="Exam" model="${calculatorInstance}" /> | ||
|
||
<div> | ||
<label> </label> | ||
<input type="submit" value="Calculate"/> | ||
</div> | ||
</fieldset> | ||
</form> | ||
|
||
|
||
<div class="padded"> | ||
<label>Result</label> | ||
<rooms:decorate grade="${calculatorInstance.result}"> | ||
<output>${calculatorInstance.result}</output> | ||
</rooms:decorate> | ||
</div> | ||
|
||
|
||
</body> | ||
</html> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package rooms | ||
|
||
import geb.spock.GebSpec | ||
import grails.testing.mixin.integration.Integration | ||
import spock.lang.Ignore | ||
|
||
/** | ||
* See http://www.gebish.org/manual/current/ for more instructions | ||
*/ | ||
@Integration | ||
@Ignore | ||
class CalculatorSpec extends GebSpec { | ||
|
||
|
||
void "Basic calculation"() { | ||
when: | ||
go '/static/GradeCalculator.html' | ||
then: | ||
title == "Grade Calculator" | ||
|
||
when: "set valid input" | ||
$("form").en = 5.0 | ||
$("form").exam = 6.0 | ||
$("input", type: "submit").click() | ||
|
||
then: "Result Page is displayed" | ||
title == "Average" | ||
// $("output").text() == "5.5" | ||
|
||
|
||
when: "click on back link" | ||
$("a", text: "calculator").click() | ||
then: | ||
title == "Grade Calculator" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package rooms | ||
|
||
import geb.spock.GebSpec | ||
import grails.testing.mixin.integration.Integration | ||
|
||
|
||
/** | ||
* See http://www.gebish.org/manual/current/ for more instructions | ||
*/ | ||
@Integration | ||
class HomeSecondSpec extends GebSpec { | ||
|
||
void "test home is there"() { | ||
when:"The home page is visited" | ||
go '/static/Home.html' | ||
then:"The title is Homepage" | ||
title == "Homepage" | ||
} | ||
|
||
void "home links to Second and Second links back"() { | ||
when:"The home page is visited" | ||
go '/static/Home.html' | ||
then:"The title is Homepage" | ||
title == "Homepage" | ||
|
||
when: "click on link to second" | ||
$("a", text: "second").click() | ||
then: "Second page is displayed" | ||
title == "Second" | ||
|
||
when: "click on back link" | ||
$("a", text: "home").click() | ||
then: "Home page is displayed, again" | ||
title == "Homepage" | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
src/integration-test/groovy/rooms/InPlaceCalculatorSpec.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package rooms | ||
|
||
import geb.spock.GebSpec | ||
import grails.testing.mixin.integration.Integration | ||
import spock.lang.Ignore | ||
|
||
/** | ||
* See http://www.gebish.org/manual/current/ for more instructions | ||
*/ | ||
@Integration | ||
@Ignore | ||
class InPlaceCalculatorSpec extends GebSpec { | ||
|
||
void "Calculate in place with a self-refreshing view"() { | ||
when: "Go to start GSP page by calling it disguised as HTML" | ||
go '/InPlaceCalculator.html?lang=en' | ||
then: | ||
title == "In-Place Calculator" | ||
|
||
when: "set valid input" | ||
$("form").en = 5.0 | ||
$("form").exam = 6.0 | ||
$("input", type: "submit").click() | ||
|
||
then: "Result is displayed with proper rounding up" | ||
$("output").text() == "6" | ||
} | ||
|
||
void "Invalid input shows error message and sets error class"() { | ||
when: "Go to start GSP page by calling it disguised as HTML" | ||
go '/InPlaceCalculator.html?lang=en' | ||
then: | ||
title == "In-Place Calculator" | ||
|
||
when: "set invalid input" | ||
$("form").en = 0.9 | ||
$("form").exam = 3.0 | ||
$("input", type: "submit").click() | ||
|
||
then: "Result contains error message" | ||
$("output").text() == "Cannot calculate. Input data was invalid." | ||
then: "invalid en field has error class while valid exam input has no class" | ||
$("#en", class:'error') | ||
$("#exam").attr('class') == "" | ||
} | ||
|
||
// TODO: un-comment the commented lines below and see them failing, then make them pass | ||
|
||
void "Invalid input is handled in-place by JS without submission"() { | ||
given: "a valid state" | ||
go '/InPlaceCalculator.html?lang=en' | ||
$("form").en = 3.0 | ||
$("form").exam = 3.0 | ||
when: | ||
$("input", type: "submit").click() | ||
then: "we should have a clean, valid state to start from" | ||
$("#en").attr('class') == "" | ||
when: "we enter some invalid value _without_ submitting" | ||
// def message = withAlert { | ||
$("form").en = 0.9 | ||
// } | ||
then: "the in-place JS logic should kick in" | ||
// $("#en").attr('class') == "error" | ||
// message == "en value needs to be at least 1.0" | ||
// $("#en").focused | ||
} | ||
|
||
|
||
} |
Oops, something went wrong.