All Projects → nullobject → mache

nullobject / mache

Licence: MIT license
A library for writing cleaner and more expressive acceptance tests using page objects.

Programming Languages

ruby
36898 projects - #4 most used programming language
Makefile
30231 projects

Projects that are alternatives of or similar to mache

capybara-chrome
Chrome driver for Capybara using Chrome's remote debugging protocol
Stars: ✭ 27 (-32.5%)
Mutual labels:  rspec, capybara
LocalSupport
A directory of local support services and volunteer opportunities
Stars: ✭ 60 (+50%)
Mutual labels:  rspec, capybara
capybara-chromedriver-logger
Enables console.log/error/info output from Javascript feature specs running with Chromedriver
Stars: ✭ 54 (+35%)
Mutual labels:  rspec, capybara
Rantly
Ruby Imperative Random Data Generator and Quickcheck
Stars: ✭ 241 (+502.5%)
Mutual labels:  rspec
Apitome
Apitome: /iˈpitəmē/ An API documentation presentation layer for RSpec API Documentation output.
Stars: ✭ 244 (+510%)
Mutual labels:  rspec
j8spec
Library that allows tests written in Java to follow the BDD style introduced by RSpec and Jasmine.
Stars: ✭ 45 (+12.5%)
Mutual labels:  rspec
saharspec
RSpec sugar to DRY your specs
Stars: ✭ 58 (+45%)
Mutual labels:  rspec
Specjour
distributed rspec & cucumber via bonjour
Stars: ✭ 214 (+435%)
Mutual labels:  rspec
r spec-clone.rb
A minimalist RSpec clone with all the essentials.
Stars: ✭ 38 (-5%)
Mutual labels:  rspec
house style
A shared house style for Ruby projects
Stars: ✭ 19 (-52.5%)
Mutual labels:  rspec
ruby-dns-mock
DNS mock server written on 💎 Ruby. Mimic any DNS records for your test environment with fake DNS server.
Stars: ✭ 50 (+25%)
Mutual labels:  rspec
solr wrapper
Wrap your tests with Solr 5+
Stars: ✭ 22 (-45%)
Mutual labels:  rspec
opal-rspec
Opal + RSpec = ♥️
Stars: ✭ 57 (+42.5%)
Mutual labels:  rspec
serverspec-extended-types
A set of extended types for ServerSpec 2.x
Stars: ✭ 28 (-30%)
Mutual labels:  rspec
Nspec
A battle hardened testing framework for C# that's heavily inspired by Mocha and RSpec.
Stars: ✭ 242 (+505%)
Mutual labels:  rspec
cypress-page-object
Represent the screens of your website as a series of objects in your Cypress test suite
Stars: ✭ 23 (-42.5%)
Mutual labels:  page-object
Rspec Nc
🚦 RSpec formatter for OS X's Notification Center
Stars: ✭ 223 (+457.5%)
Mutual labels:  rspec
rspec html reporter
Rspec custom formatter to produce beautiful reports from rspec
Stars: ✭ 32 (-20%)
Mutual labels:  rspec
turbo tests
Run RSpec tests on multiple cores. Like parallel_tests but with incremental summarized output. Originally extracted from the Discourse and Rubygems source code.
Stars: ✭ 81 (+102.5%)
Mutual labels:  rspec
rspec-tap-formatters
TAP Producer for RSpec-3
Stars: ✭ 20 (-50%)
Mutual labels:  rspec

Mâché

Build Status

Mâché (pronounced "mash-ay") is a tool that helps you to write cleaner and more expressive acceptance tests for your Ruby web applications using page objects.

Table of Contents

What is a Page Object?

A page object is a data structure that provides an interface to your web application for the purposes of test automation. For example, it could represent a single HTML page, or perhaps even a fragment of HTML on a page.

From Martin Fowler:

A page object wraps an HTML page, or fragment, with an application-specific API, allowing you to manipulate page elements without digging around in the HTML.

Capybara can get us part of the way there. It allows us to work with an API rather than manipulating the HTML directly, but what it provides isn't an application specific API. It gives us low-level API methods like find, fill_in, and click_button, but it doesn't provide us with high-level methods to do things like "sign in to the app" or "click the Dashboard item in the navigation bar".

This is where page objects come in. Using Mâché, we can define a page object class called SignInPage and use it any time we want to automate authenticating with our app. It could handle visiting the sign in page, entering the user's credentials, and clicking the "Sign in" button.

Getting Started

Let's dive straight in and take a look at an example. Consider the following HTML fragment for the welcome page in our app:

<html>
  <body>
    <header>
      <h1>Welcome</h1>
      <div id="flash" class="notice">lorem ipsum</div>
    </header>
    <nav>
      <ul>
        <li><a href="/foo" class="selected">foo</a></li>
        <li><a href="/bar">bar</a></li>
        <li><a href="/baz">baz</a></li>
      </ul>
    </nav>
    <main>
      lorem ipsum
    </main>
  </body>
</html>

To define a WelcomePage page object class to wrap this HTML page, we extend the Mache::Page class. The only method our class needs to provide is path, this tells Mâché where to go when we want to visit the page:

require "mache"

class WelcomePage < Mache::Page
  def path
    "/welcome"
  end
end

We can visit our welcome page using our page object:

page = WelcomePage.visit
page.current? # true

Mâché also handily exposes the Capybara API on our page object:

page.find("main").text # "lorem ipsum"

Elements

To make our page object more useful, we can define an element on our page object class using the element macro. An element is simply an HTML element that we expect to find on the page using a CSS selector.

Let's define a main element to represent the main section of our HTML page:

require "mache"

class WelcomePage < Mache::Page
  element :main, "main"

  def path
    "/welcome"
  end
end

We can query the main element as an attribute of our page object:

page.main.text # "lorem ipsum"

Components

For elements that can be shared across any number of page object classes it may be useful to define a reusable component by extending the Mache::Node class. A component can contain any number of elements (or even other components).

Let's define a Header component to represent the header of our HTML page:

require "mache"

class Header < Mache::Node
  element :title, "h1"
end

We can mount the Header component in our page object class at a given CSS selector using the component macro:

require "mache"

class WelcomePage < Mache::Page
  component :header, Header, "header"
  element :main, "main"

  def path
    "/welcome"
  end
end

Querying a component of our page object is much the same as with an element:

page.header.title.text # "Welcome"

Helpers

Mâché provides helpers for testing Rails apps.

Flash

The Flash helper provides methods for testing flash messages. First define a flash in your page object class:

require "mache"
require "mache/helpers/rails"

class WelcomePage < Mache::Page
  include Mache::Helpers::Rails::Flash

  flash "#flash"
end

Then you can query the flash on your page object:

page.has_message?(:success, "lorem ipsum")
page.has_message?(:success, /lorem ipsum/)

There are even convenience matchers for the common types of flash messages:

page.has_success_message?("lorem ipsum")
page.has_notice_message?("lorem ipsum")
page.has_alert_message?("lorem ipsum")
page.has_error_message?("lorem ipsum")

Routes

The Routes helper mixes the Rails URL helpers into your page object class. This allows you to use the *_path and *_url methods as you normally would in your Rails.

require "mache"
require "mache/helpers/rails"

class WelcomePage < Mache::Page
  include Mache::Helpers::Rails::Routes

  def path
    welcome_path
  end
end

Examples

Let's look at an example of an acceptance test for our WelcomePage. Note that the Header, NavItem, and Nav components can be reused in any other page object classes we may define later for our web application.

require "mache"
require "mache/helpers/rails"

class Header < Mache::Node
  element :title, "h1"
end

class NavItem < Mache::Node
  def selected?
    node[:class].include?("selected")
  end
end

class Nav < Mache::Node
  components :items, NavItem, "a"

  def selected_item
    items.find(&:selected?)
  end
end

class WelcomePage < Mache::Page
  include Mache::Helpers::Rails::Flash
  include Mache::Helpers::Rails::Routes

  component :header, Header, "header"
  component :nav, Nav, "nav"
  element :main, "main"
  flash "#flash"

  def path
    welcome_path
  end
end

feature "Welcome page" do
  let(:home_page) { WelcomePage.visit }

  scenario "A user visits the welcome page" do
    expect(home_page).to be_current

    # header
    expect(home_page).to have_header
    expect(home_page.header.title).to eq("Welcome")

    # nav
    expect(home_page).to have_nav
    expect(home_page.nav).to have_items
    expect(home_page.nav.items.count).to be(3)
    expect(home_page.nav.items[0].text).to eq("foo")
    expect(home_page.nav.items[1].text).to eq("bar")
    expect(home_page.nav.items[2].text).to eq("baz")
    expect(home_page.nav.selected_item).to eq("foo")

    # main
    expect(home_page.main.text).to eq("lorem ipsum")

    # flash
    expect(home_page).to have_flash
    expect(home_page).to have_notice_message("lorem ipsum")
  end
end

Documentation

Read the API reference on RubyDoc.

License

Mâché is licensed under the MIT License.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].