Index: branches/features/purchaseOrders/test/functional/GebReportingSpecBase.groovy
===================================================================
--- branches/features/purchaseOrders/test/functional/GebReportingSpecBase.groovy	(revision 947)
+++ branches/features/purchaseOrders/test/functional/GebReportingSpecBase.groovy	(revision 948)
@@ -1,6 +1,13 @@
 import geb.spock.GebReportingSpec
+import gnumims.functional.pages.HomePage
+import gnumims.functional.pages.LoginPage
 
 /**
- *
+ * Provides a base class for functional testing.
+ * Significantly speedup functional test development:
+ *  Run `grails test run-app`.
+ *  In a separate process run `grails interactive`
+ *  At the prompt `test-app functional: -baseUrl=http://localhost:8080/gnuMims -echoOut`
+ *  Hit enter to repeat tests very quickly.
  */
 class GebReportingSpecBase extends GebReportingSpec {
@@ -8,3 +15,24 @@
     String getBaseUrl() { "http://localhost:8080/$appName/" }
     File getReportDir() { new File("target/test-reports/geb-pages") }
+
+    /**
+     * Logs into the application either via a target page that requires
+     * authentication or by directly requesting the login page.
+     */
+    def login(username, password, targetPage = null, params = [:]) {
+        if (targetPage) {
+            to([*:params], targetPage)
+            page LoginPage
+        }
+        else {
+            to LoginPage
+        }
+
+        form.j_username = username
+        form.j_password = password
+
+        //if (targetPage) login.click(targetPage)
+        if (targetPage) loginButton.click(HomePage) // gnuMims will always start at HomePage.
+        else loginButton.click(HomePage)
+    }
 }
Index: branches/features/purchaseOrders/test/functional/LoginSpec.groovy
===================================================================
--- branches/features/purchaseOrders/test/functional/LoginSpec.groovy	(revision 947)
+++ branches/features/purchaseOrders/test/functional/LoginSpec.groovy	(revision 948)
@@ -15,10 +15,7 @@
     }
 
-    def "When we click login we go to the home page"() {
+    def "When we login, we go to the home page"() {
         when:
-        to LoginPage
-        form.j_username = "admin"
-        form.j_password = "pass"
-        login.click()
+        login('admin', 'pass')
 
         then:
@@ -26,5 +23,5 @@
     }
 
-    def "When we click logout, we go to the logout page"() {
+    def "When we logout, we go to the logout page"() {
         when:
         logout.click()
@@ -37,8 +34,5 @@
     def "If we type in the wrong password"() {
         when:
-        to LoginPage
-        form.j_username = "admin"
-        form.j_password = "bogus"
-        login.click()
+        login('admin', 'bogus')
 
         then:
Index: branches/features/purchaseOrders/test/functional/gnumims/functional/pages/LoginPage.groovy
===================================================================
--- branches/features/purchaseOrders/test/functional/gnumims/functional/pages/LoginPage.groovy	(revision 947)
+++ branches/features/purchaseOrders/test/functional/gnumims/functional/pages/LoginPage.groovy	(revision 948)
@@ -6,5 +6,5 @@
 
     static content = {
-        login(to:HomePage) { $('#loginForm input[value=Login]') }
+        loginButton(to:HomePage) { $('#loginForm input[value=Login]') }
         form { $("#loginForm") }
         password { $("input[name=j_password]").value() }
