         browser.navigate().back().then ->
           # Resolve to the URL.
           home_url
-    
-      find()
+
+      findButton()
         .then(validate)
         .then(click)
         .then(pop)
-  
+
   # @returns the help content
   help:
     get: ->
-      @select('.qi-help').then (block) =>
+      @find('.qi-help').then (elt) =>
         # Help is initially hidden.
-        expect(block.isDisplayed(), 'The help element is not initially hidden')
+        expect(elt, 'The help element is missing').to.exist
+        expect(elt.isDisplayed(), 'The help element is not initially hidden')
           .to.eventually.be.false
         # The help button is the parent of the question mark icon.
-        @select('button .glyphicon-question-sign', '..').then (button) =>
+        @find('button .glyphicon-question-sign', '..').then (button) ->
           expect(button, 'The help button is missing').to.exist
           # Open the help view...
           button.click().then =>
             # ...verify that the help is displayed...
-            expect(block.isDisplayed(), 'The help element is hidden after click')
+            expect(elt.isDisplayed(), 'The help element is hidden after click')
               .to.eventually.be.true
-            # ...find the element...
-            @select('.qi-main .qi-help-text').then (content) =>
+            # ...find the help text element...
+            elt.find('.qi-help-text').then (content) ->
               # ...resolve to the formatted help content.
-              content.getInnerHtml()
-    
-    # @returns the contact information contact
-    contact: () ->
-      @select('.qi-main .qi-contact-info').then (content) =>
-        # ...resolve to the formatted contact information content.
-        content.getInnerHtml()
+              content.getInnerHtml() if content?
+
+  # @returns the contact information
+  contactInfo:
+    get: ->
+      @find('.qi-contact-info').then (content) ->
+        content.getInnerHtml() if content?
 
 module.exports = Page

#   login = LoginPage('/login')
#   expect(login.billboard).to.evantually.equal('Login')
class Page
  # @param url the page request URL
  constructor: (url) ->
    # Fire off the browser request.
    browser.get(url)
    
    # The title is resolved when the page is loaded.
    @title = browser.getTitle()
    
    # The billboard text.
    @billboard = @text('.qi-billboard', 'h3')
    
  # Finds the element with the given search selection chain.
  # Each selector is a By locator or search string. The search
  # string can be CSS or xpath. If the string contains a '/' or
  # equals '..', then the string is assumed to be an xpath,
  # otherwise, it is assumed to be CSS.
  #
  # For example,
  #
  #     page.select('.qi-billboard', 'h3', '..')
  #
  # returns the parent of the h3 element within the .qi-billboard
  # element on the page.
  #
  # @param selectors the selectors
  # @returns a promise which resolves to the target
  #   ElementFinder, or null if no such element exists
  select: (selectors...) ->
    # @param selectors the search chain conditions
    # @returns the By locator object
    locator = (selector) -> 
      # If the selector is a string, then make a By locator.
      # Otherwise, the selector is assumed to already be a
      # By locator.
      if _.isString(selector)
        # An xpath selector string has a slash or equals.
        # An id selector starts with # and doesn't have a space.
        # Anything else is assumed to be CSS.
        if selector is '..' or '/' in selector
          By.xpath(selector)
        else if selector[0] is '#' and not ' ' in selector
          By.id(selector[1..-1])
        else
          By.css(selector)
      else
        selector

    # @param parent the ElementFinder wrapper to search, or
    #   null if no parent
    # @param locator the protractor By object
    # @returns the result of calling element on the locator
    #   relative to the given parent finder
    find = (parent, locator) ->
      parent.element(locator)

    # Convert the selectors to locators.
    locators = ((locator(selector) for selector in selectors))
    # The initial locator.
    locator = locators.shift()
    # The initial ElementFinder.
    finder = element(locator)
    # Chain the selects.
    target = _.reduce(locators, find, finder)
    
    # Return a promise which guards the result with an
    # existence check.
    target.isPresent().then (exists) ->
      if exists then target else null

  # @param selectors the target search selectors
  # @returns a promise which resolves to the element's visible
  #   text, or null if the search result does not exist
  text: (selectors...) ->
    # Find the element.
    @select(selectors...).then (target) ->
      if target? then target.getText() else null

# Add the virtual properties.
Object.defineProperties Page.prototype,
  # Navigate to the home page by clicking the home button.
  #
  # @returns the home URL

_ = require 'lodash'

expect = require('./expect')()

