Class: Kookaburra::UIDriver::UIComponent Abstract

Inherits:
SimpleDelegator
  • Object
show all
Extended by:
HasUIComponents
Includes:
Assertion
Defined in:
lib/kookaburra/ui_driver/ui_component.rb,
lib/kookaburra/ui_driver/ui_component/address_bar.rb

Overview

This class is abstract.

Unless you override the default implementation of #url, you must override the #component_path method if you want the component to be navigable by the AddressBar component.

Note:

Even though a UIComponent should respond to all of the methods on the browser (i.e. all of the Capybara DSL methods), for some reason call to #select get routed to Kernel#select. You can get around this by calling it as self.select. See https://gist.github.com/3192103 for an example of this behavior.

UIComponent is intended to be subclassed to represent each component of your application-under-test's user interface. The purpose of the UIComponent object is to abstract away the implementation details of your interface when testing and allow you to concentrate on testing your business requirements. For instance, a UIComponent subclass for your sign-up form might have accessors for the individual fields as well as methods that allow you to perform distinct operations:

Note that the "browser operation" methods such as #fill_in and #click_button are delegated to a ScopedBrowser and are automatically scoped to the component's DOM element.

Examples:

SignUpForm component

class SignUpForm < Kookaburra::UIDriver::UIComponent
  def component_path
    '/signup'
  end

  # If it can't be inferred from the class name
  def component_locator
    '#user-sign-up'
  end

  def email
    find('#user_email').value
  end

  def email=(new_email)
    fill_in 'user_email', :with => new_email
  end

  def password
    find('#user_password').value
  end

  def password=(new_password)
    fill_in 'user_password', :with => new_password
  end

  def password_confirmation
    find('#user_password_confirmation').value
  end

  def password_confirmation=(new_password_confirmation)
    fill_in 'user_password_confirmation', :with => new_password_confirmation
  end

  def submit
    click_button 'Sign Up'
  end

  def (data = {})
    self.email = data[:email]
    self.password = data[:password]
    self.password_confirmation = data[:password_confirmation]
    submit
  end
end

Direct Known Subclasses

AddressBar

Defined Under Namespace

Classes: AddressBar

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from HasUIComponents

ui_component

Methods included from Assertion

#assert

Constructor Details

#initialize(configuration, options = {}) ⇒ UIComponent

New UIComponent instances are typically created for you by your Kookaburra::UIDriver instance.

Parameters:

See Also:

  • Kookaburra::UIDriver.ui_component


98
99
100
101
102
103
104
105
106
# File 'lib/kookaburra/ui_driver/ui_component.rb', line 98

def initialize(configuration, options = {})
  @configuration = configuration
  @options = options
  @browser = configuration.browser
  @app_host = configuration.app_host
  @server_error_detection = configuration.server_error_detection
  scoped_browser = ScopedBrowser.new(@browser, lambda { component_locator })
  super(scoped_browser)
end

Instance Attribute Details

#browserObject (readonly, protected)

The browser object from the initialized configuration



134
135
136
# File 'lib/kookaburra/ui_driver/ui_component.rb', line 134

def browser
  @browser
end

#configurationObject (readonly)

The Configuration with which the component instance was instantiated.



84
85
86
# File 'lib/kookaburra/ui_driver/ui_component.rb', line 84

def configuration
  @configuration
end

#optionsObject (readonly)

The options Hash with which the component instance was instantiated.



88
89
90
# File 'lib/kookaburra/ui_driver/ui_component.rb', line 88

def options
  @options
end

Instance Method Details

#component_locatorString (protected)

The CSS3 selector that will find the element in the DOM

Defaults to a "#" followed by the snake-cased (underscored) version of the class name with '/' replaced by '-'. Override this method in your subclasses if you need a different CSS3 selector to find your component.

Examples:

class My::Awesome::ComponentThingy < Kookaburra::UIDriver::UIComponent
end

x = My::Awesome::ComponentThingy.allocate
x.send(:component_locator)
#=> '#my-awesome-component_thingy'

Returns:

  • (String)


159
160
161
162
163
164
165
166
# File 'lib/kookaburra/ui_driver/ui_component.rb', line 159

def component_locator
  "#" + self.class.name.gsub(/::/, '/').
    gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
    gsub(/([a-z\d])([A-Z])/,'\1_\2').
    tr("-", "_").
    gsub('/', '-').
    downcase
end

#component_pathString (protected)

This method is abstract.

Returns the URL path that should be loaded in order to reach this component.

Returns:

  • (String)

    the URL path that should be loaded in order to reach this component

Raises:

  • (Kookaburra::ConfigurationError)

    raised if you haven't provided an implementation



140
141
142
# File 'lib/kookaburra/ui_driver/ui_component.rb', line 140

def component_path
  raise ConfigurationError, "You must define #{self.class.name}#component_path."
end

#detect_server_error!Object (protected)

Runs the server error detection function specified in Configuration#server_error_detection.

It's a noop if no server error detection was specified.

Raises:

  • (UnexpectedResponse)

    raised if the server error detection function returns true



175
176
177
178
179
180
# File 'lib/kookaburra/ui_driver/ui_component.rb', line 175

def detect_server_error!
  return if @server_error_detection.nil?
  if @server_error_detection.call(browser)
    raise UnexpectedResponse, "Server Error Detected:\n#{browser.text}"
  end
end

#not_visible?Boolean

Note:

This does not check for a server error.

The opposite of #visible?

Returns:

  • (Boolean)


121
122
123
# File 'lib/kookaburra/ui_driver/ui_component.rb', line 121

def not_visible?
  browser.has_no_css?(component_locator, visible: true)
end

#this_elementObject (protected)

Provides a reference to the HTML element represented by this UIComponent

This is useful for getting at attributes of the current element, because the normal find methods are scoped to run inside this element.

Returns:

  • Capybara::Element



190
191
192
# File 'lib/kookaburra/ui_driver/ui_component.rb', line 190

def this_element
  browser.find(component_locator)
end

#url(*args) ⇒ Object

Returns the full URL by appending #component_path to the value of the Configuration#app_host from the initialized configuration.



127
128
129
# File 'lib/kookaburra/ui_driver/ui_component.rb', line 127

def url(*args)
  "#{@app_host}#{component_path(*args)}"
end

#visible?Boolean

Is the component's element found on the page and is it considered "visible" by the browser driver?

Returns:

  • (Boolean)


110
111
112
113
114
115
116
# File 'lib/kookaburra/ui_driver/ui_component.rb', line 110

def visible?
  visible = browser.has_css?(component_locator, visible: true)
  unless visible
    detect_server_error!
  end
  visible
end