Saturday, 22 March 2008

grails-selenium-0.4

This information is out of date - please see http://www.grails.org/Selenium+plugin



Version 0.4 of the grails selenium plugin is now available.

This version adds:

  • scripts to create and run tests

  • a postResults url for displaying the final test results


Details are as follows:

run-selenium
Runs Selenium in the specified browser.
Specify the path to your browser as a command line parameter i.e.
grails run-selenium /usr/bin/firefox

or, if the executable is on the path you would just need
grails run-selenium firefox

In your application.properties, you can specify:
selenium.auto=true
selenium.close=true
selenium.multiWindow=true
selenium.highlight=true
selenium.resultsUrl=/your/url/here (defaults to ${appContext}/selenium/postResults)
selenium.runInterval=1000
selenium.baseUrl=

See http://selenium.openqa.org/installing.html (section titled Continuous Integration) for more information on selenium and continuous integration.
create-selenium-test
Generates a new empty selenium test.

Supply the path of the test you want to create, relative to 'web-app/selenium/tests'. The extension of this must be one of html, psv, gsp. The test file will be created using the syntax based on the file extension.

Example use:
grails create-selenium-test registration/errors/InvalidUsername.gsp

creates
web-app/selenium/tests/registration/errors/InvalidUsername.gsp

create-selenium-domain-test
Generates a new selenium test for the given domain class.

Supply the name of the domain class you want to test, followed by and extension that identifies the sytax to use. The extension of this must be one of html, psv, gsp.

Example use:
grails create-selenium-domain-test book.gsp

creates
web-app/selenium/tests/book.gsp

The generated test exercises the default grails scaffolding for CRUD functionality.

postResults page
A basic postResults page is provided, and if required the results can be saved to xml.

When using grails run-selenium, you can add properties to application.properties:

  • selenium.auto=true

  • selenium.resultsUrl=/your/url/here (defaults to ${appContext}/selenium/postResults)

  • selenium.saveXmlTo=/tmp/selenium.xml


By default resultsUrl is set as  ${appContext}/selenium/postResults which is provided as a basic HTML implementation. Nothing fancy.

Download here or install with
grails install-plugin http://www.javathinking.com/grails/grails-selenium-plugin/0.4/grails-selenium-0.4.zip

Friday, 21 March 2008

grails-jsunit-0.1

This information is out of date - please see http://www.grails.org/jsUnit+plugin


grails-jsunit provides an easy and convenient way to utilize the JsUnit framework to your grails application. JsUnit allows you to unit test JavaScript functions in a similar way to using JUnit for Java.

To install the plugin, use:

grails install-plugin http://www.javathinking.com/grails/grails-jsunit-plugin/0.1/grails-jsunit-0.1.zip

This plugin adds the following new scripts:

create-jsunit-test
Generates a new empty jsunit test. Supply the path of the test you want to create, relative to 'test/jsunit/tests'.
Example use:
grails create-jsunit-test registration/mytest

creates
${basedir}/test/jsunit/tests/registration/mytest.html


run-jsunit
Runs JsUnit in the specified browser. Specify the path to your browser as a command line parameter i.e.
grails run-jsunit /usr/bin/firefox

or, if the executable is on the path you would just need
grails run-jsunit firefox


In your application.properties, you can specify:
jsunit.autoRun=true


When executing this script, it overwrites ${basedir}/test/jsunit/suiteAll.html to build a suite that references all tests in ${basedir}/test/jsunit/test.

Sunday, 16 March 2008

Firefox profiles

If you share a login with someone else (ie. family) Firefox profiles can be very useful. Likewise, if you are a developer and you have several different contexts or modes of operation, profiles can make life a lot easier.

I use them at home with family members - you can set each person up with their own profile, so all you have to do is restart Firefox (rather than logging out out of the operating system and then back on as someone else). Firefox will prompt you - asking who you want to be right now.

At work, how many times have you cleared all of your private settings while debugging, just to see if the problem is related to caching or some other previous state. Creating a profile is much easier - especially since you probably want to stay logged in to all of those websites you use every day.

Just start firefox from the command line with the parameter '-profilemanager' - you'll be prompted with a dialog so you can mange your profiles.

Read more about it here :

Looking for IT work in Australia? JobReel.com.au!

I'm currently looking for contract work, and all of the usual places offer vague job descriptions that makes it hard to differentiate one from the other. This makes it hard to decide which ones to apply for, and almost always mean that you end up applying for jobs that are totally inappropriate.

Now there is JobReel.com.au - much along the lines of jobs.joelonsoftware.com, positions must display the employer.

I'm still looking for a site that lets me specify location, price range, responsibilities and technologies - but JobReel is closer than any of the others, and from what I've seen so far, the job descriptions are more useful and realistic.

It looks relatively new to the scene - good luck!

Ohloh.net

I just discovered http://www.ohloh.net/ - this is a great site, I think the easiest way I can describe it is by saying it is like linkedin.com, but based on opensource projects. You can create an account, and then add opensource projects to your 'stack'.

You can:

  • see geographically where people with a particular project on their stack are located

  • add your experience to your profile to build your resume

  • view statistics for different languages and projects.


This is a very interesting site, and it will be interesting to see where it goes. Check out my profile.

Friday, 14 March 2008

grails-selenium-0.3

Version 0.3 of the grails selenium plugin is now available.

This version:

  • Adds GSP support for writing tests

  • Fixes bug where hidden directories were shown as suites

  • Fixes bug on windows with invalid URIs to html tests


To use GSP to generate the tests, use the <sel:test> tag, followed by nested <sel:row> tags.

<sel:row> can take either:

  • one 'line' attribute where the command, target and value are pipe separated as per the pipe separated value files

  • or separate 'command', 'target', and 'value' attributes.


Because this is a normal GSP file, you have full access to the normal variables and you could call other classes for utility methods.

An example GSP test:

<g:set var="bookTitle" value="book0d"/>
<sel:test name="MyTest">
<sel:row command="open" target="${request.contextPath}"/>
<sel:row line="clickAndWait|link=BookController"/>
<sel:row line="clickAndWait|link=New Book"/>
<sel:row command="type" target="title" value="${bookTitle}"/>
<sel:row line="clickAndWait|//input[@value='Create']"/>
<sel:row line="clickAndWait|link=Book List"/>
<sel:row line="verifyTextPresent|${bookTitle}"/>
</sel:test>

Download grails-selenium-0.3.zip

Also see:

Wednesday, 12 March 2008

grails-jttaglib-0.1

grails-jttaglib plugin is a small collection of convenience tags.

The sample code below assumes you have a domain class that looks like this:
 class Book {
String title="my new book"
String content

static def constraints = {
title(maxSize:20)
content(maxSize:200)
}
}

When using these tags, you must have the following in the page - normally in the head block:
<g:javascript library="prototype"/>

<jttext:script />

textArea

Creates a TextArea HTML element, where the maximum number of characters is
limited by the constraints on the domain object, and tabs can be allowed if
desired.

Sample use:
<jttext:textArea object="${new Book()}" name="content" allowTabs="true"/>

<jttext:statusDiv for="content" />

The number of remaining characters available are displayed in the status div.
If allowTabs is set to true, tabs can be entered in the text area.

textField

Creates a text input type using maxlength from the objects constraints.
Sample use:
<jttext:textField object="${book}" name="title"/>

Generates:
<input type="text" name="title" maxlength="20" value="my new book" id="title" />

Download grails-jttaglib-0.1.zip

Regression testing grails plugins

For regression testing the grails plugins I've released, I have a shell script that:

  1. cleans up any previous runs

  2. packages the current code for the plugin OR downloads a release from my web site

  3. creates a new grails app

  4. copies preprepared resources into this new grails app

  5. installs the plugin


Now all I have to do is run the application and test it through the browser (potential for selenium to help here?). This is great for testing the plugin against a new grails version, or just for testing code changes to the plugin itself.

I put the script in <project_home>/test/regression/run.sh and the resources in <project_home>/test/regression/resources. The resources directory contains files like domain objects etc in the same directory layout as a normal grails project. This way I just need to copy the contents of the resources directory over the top of my newly created project.

I should have written it as an ANT script though (what was I thinking?) - then it would be platform independent. I'll migrate it to ANT soon.

I'd appreciate any comments about the process though - is it useful to you?

Download the script here. Use it with care, it does delete some directories.

Regression testing grails plugins

For regression testing the grails plugins I've released, I have a shell script that:

  1. cleans up any previous runs

  2. packages the current code for the plugin OR downloads a release from my web site

  3. creates a new grails app

  4. copies preprepared resources into this new grails app

  5. installs the plugin


Now all I have to do is run the application and test it through the browser (potential for selenium to help here?). This is great for testing the plugin against a new grails version, or just for testing code changes to the plugin itself.

I put the script in <project_home>/test/regression/run.sh and the resources in <project_home>/test/regression/resources. The resources directory contains files like domain objects etc in the same directory layout as a normal grails project. This way I just need to copy the contents of the resources directory over the top of my newly created project.

I should have written it as an ANT script though (what was I thinking?) - then it would be platform independent. I'll migrate it to ANT soon.

I'd appreciate any comments about the process though - is it useful to you?

Download the script here. Use it with care, it does delete some directories.

Tuesday, 11 March 2008

Allowing tabs in a text area

In addition to controlling the maximum number of characters in a text area, I also want to allow the user to enter tabs. But default, hitting tab would move out of the text area to the next control on the page.

Overriding this behavior can be done by using the onKeyDown event controller so you can:

  1. check if the tab key has been pressed

  2. if it has, insert a tab at the current cursor location

  3. put focus back into the text area


I've extended my little TextAreaTagLib to handle an 'allowTabs' attribute. Now you can allow tabs to be entered just by using allowTabs="true". I've also incorporated the work from the TextField modification so that the number of characters can be limited based on the maxSize constraint on the object.

Sample use:
<g:javascript library=”prototype”/>
<jttext:script />
...
<jttext:textArea object="${new Book()}" name="content" allowTabs="true"/>
<jttext:statusDiv for="content" />

Please note: I've now called the tag lib JTFormTagLib.groovy, and it has both the TextArea and the TextField code in it.

Download here.

Also, I've thought about creating it as a plugin, but it's kind of small to warrant a plugin by itself - what do you think?

Allowing or denying self registration with grails-acegi plugin

The grails-acegi-0.2 plugin is great - it adds login, user management, and user registration capabilities to your application in seconds. However, I'm building a web application where I want to be able to let the deployment team decide whether users can register themselves or alternatively, have an administrator create users. I want provide these settings without the deployment unit (the WAR file) having to be modified.

I currently have a properties file for each server (DEV, STAGE, PROD) which defines properties specific to the environment - such as the email server and username/password etc. In this properties file, I also have application settings which are relevant to that environment. So, this is a good place to define a property:

myapp.registration.enabled=false


Grails has an excellent configuration strategy, and in my applications Config.groovy all I have to do is specify the external config locations:

grails.config.locations = ["file:${System.getProperty('myapp.properties')}"]


I've referenced a system property, so anyone deploying my application just needs to use the -D jvm option - when running with grails all we have to do is:

grails -Dmyapp.properties=/server/env/prod/server.properties


Now I just need to modify the RegistrationController.groovy to check this property:

def index = {
//if logon user.
if(authenticateService.userDomain()!=null){
log.info("${authenticateService.userDomain()} user hit the register page")
redirect(action:"show")
return
}

if(!(grailsApplication.config.jtchat.registration.enabled=='false')) {
def person = new Person()
person.properties = params
return ['person': person]
} else {
redirect(uri:'/')
}
}


And that's it. An easy way to provide settings to an application without modifying the WAR. Grails rocks!

Friday, 7 March 2008

Maxlength HTML attribute for domain objects

With Grails domain classes, constraints can be specified - including the maximum size of a String. For example:

class Book {
String title

static def constraints = {
title(maxSize:20)
}
}

When using 'grails generate-all' to create scaffolding, you'll notice that create.gsp and add.gsp hardcode the maxlength attribute:
<input type="text" maxlength="20" id="title" name="title"
value="${fieldValue(bean:book,field:'title')}"/>

It is possible to directly reference the constraint, meaning that the maxlength attribute is not hardcoded - and thus only defined once (in the domain object):
<input type="text" maxlength="${Book.constraints.title.getMaxSize()}"
id="title" name="title"
value="${fieldValue(bean:book,field:'title')}"/>

In fact, we can go even further and create a tag where we pass in the object itself, and the name (which matches the property name) and we can dynamically generate the maxlength and value attributes.

So when editing a book with the title set to 'my new book', the following code:
<jttext:textField object="${book}" name="title"/>

produces the following HTML:
<input type="text" name="title" maxlength="20" value="my new book"
id="title" />

The tag library to produce this is as follows:

import org.codehaus.groovy.grails.plugins.web.taglib.FormTagLib

class TextTagLib extends FormTagLib {
static namespace = "jttext"

def textField = {attrs ->
attrs.type = "text"
attrs.tagName = "textField"

def object = attrs.remove('object')
def maxlength = object.constraints."${attrs.name}".getMaxSize()
if(maxlength) {
attrs.put('maxlength', maxlength)
}
attrs.put('value', fieldValue(bean:object,field:attrs.name))

def result = field(attrs)
if (result) {
out << result
}
}
}

It makes sense to me that the tag does all of the work - it reduces duplication and makes the code more readable.

What do you think?

Thursday, 6 March 2008

Limiting the content of a TextArea

Being able to limit the length of the content entered into a TextArea can be useful for various reasons. Although not supported natively by HTML, you can achieve the same effect using Javascript - on KeyUp and KeyDown events, check the length of the textarea value and truncate if necessary. We can also display how many characters are remaining if we want to provide user feedback.

Because I've used this technique in several Grails applications, I've created a simple TagLib - you may want to customize it to your requirements.

To use it:

  • include the prototype library with <g:javascript library="prototype"/>

  • use <jttext:changeScript /> once on your page for the utility script

  • define your textarea including the maxlength attribute with <jttext:textArea id="messageField" maxlength="20" />

  • use <jttext:statusDiv for="messageField" /> to display the status message showing how many characters are left


So, a simple GSP would look like:

<html>
<head>
<g:javascript library="prototype"/>
<jttext:changeScript />
</head>

<body>

<jttext:textArea name="messageField" class="sized" style="width:320px;height:60px;" maxlength="20" />
<jttext:statusDiv for="messageField" />

</body>
</html>

Effectively what you get looks like this (the HTML code has been slightly modified to work in this post):


 


Download TagLib here.

mappings closure does not exists for class UrlMappings

I've just started working on a new grails application, and early in the piece I hit this error:
2008-03-05 18:39:20.715::WARN: Failed startup of context org.mortbay.jetty.webapp.WebAppContext@1fcb845{/jtchat,/home/prule/workspace/jtchat/web-app}
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grailsUrlMappingsHolder': Cannot resolve reference to bean 'urlMappingsTargetSource' while setting bean property 'targetSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'urlMappingsTargetSource': Cannot resolve reference to bean 'grailsUrlMappingsHolderBean' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grailsUrlMappingsHolderBean': Invocation of init method failed; nested exception is java.lang.RuntimeException: mappings closure does not exists for class UrlMappings

I'd not done much except for adding a domain class, controller, view and a test. Certainly I hadn't done anything with UrlMappings. I did have a failure installing a plugin (the converter plugin which apparently is not needed anymore?), and I am editing the project in Eclipse with the Groovy plugin.

I've no idea what caused it, but doing a 'grails clean' resolved it.

Wednesday, 5 March 2008

Sun Tech Days 2008

I'm currently attending the Sun Tech Days conference in Sydney. These events can be good for exposure to things not already on your radar, and also for catching up with colleagues you haven't seen for a while.

Some of the presentations are online if you are interested.

There is a session on 'Grails as an application framework: pros and cons' tomorrow - but so far there has no mention of Groovy or Grails (but plenty of references to JRuby, Ruby, Python, PHP, Javascript).

Update 1 :

  • Mike Cannon-Brookes presented Grails - this was a good introduction for anyone new to Grails. It appears he is very enthusiastic about it and Atlassian are using it to some extent internally.

Saturday, 1 March 2008

grails-selenium-0.2

I've just uploaded a new version of my Selenium plugin for Grails. You can download it from http://www.javathinking.com/grails/grails-selenium-plugin/0.2/grails-selenium-0.2.zip. The only significant enhancement is to support tests nested in directories.

Now, the suite page displays a list of all of the directories in the tests location. The default (top level) suite shows all tests in all directories. You can click anywhere in this suite heirarchy to load only those tests in that directory.

Let me know what you think of this implementation. There are probably several different ways to go about handling the directory structure, and this is just one implementation. I hope you find it useful!

(for more complete information about this plugin, see grails-selenium-0.1.