Skip to content

Instantly share code, notes, and snippets.

@bobanj
Forked from steveclarke/capybara.md
Created July 6, 2012 23:14
Show Gist options
  • Save bobanj/3063329 to your computer and use it in GitHub Desktop.
Save bobanj/3063329 to your computer and use it in GitHub Desktop.

Revisions

  1. @steveclarke steveclarke revised this gist Apr 15, 2012. 1 changed file with 9 additions and 0 deletions.
    9 changes: 9 additions & 0 deletions shoulda-matchers.md
    Original file line number Diff line number Diff line change
    @@ -22,6 +22,7 @@ it { should_not have_db_column(:admin).of_type(:boolean) }
    it { should have_db_column(:salary).
    of_type(:decimal).
    with_options(:precision => 10, :scale => 2) }
    it { should have_db_column(:id).with_options(:primary => true) }

    it { should have_db_index(:age) }
    it { should have_db_index([:commentable_type, :commentable_id]) }
    @@ -34,6 +35,10 @@ it { should have_many(:enemies).dependent(:destroy) }
    it { should have_one(:god) }

    it { should have_readonly_attribute(:password) }

    it { should query_the_database(4.times).when_calling(:complicated_method) }
    it { should query_the_database(4.times).or_less.when_calling(:complicated_method) }
    it { should_not query_the_database.when_calling(:complicated_method) }
    ```

    ActiveModel Matchers
    @@ -47,6 +52,7 @@ describe Post do
    it { should validate_presence_of(:body).with_message(/wtf/) }
    it { should validate_presence_of(:title) }
    it { should validate_numericality_of(:user_id) }
    it { should validate_numericality_of(:user_id).only_integer }
    it { should validate_acceptance_of(:eula) }

    it { should validate_format_of(:name).
    @@ -56,6 +62,7 @@ describe Post do
    not_with('12D45').
    with_message(/is not optional/) }
    it { should validate_numericality_of(:age) }
    it { should validate_confirmation_of(:password) }


    # validates_uniqueness_of requires an entry to be in the database already
    @@ -100,6 +107,7 @@ describe PostsController, "#show" do
    it { should respond_with(:success) }
    it { should render_template(:show) }
    it { should_not set_the_flash }
    it { should set_the_flash[:alert].to("Password doesn't match") }
    end
    end

    @@ -155,4 +163,5 @@ it { should have_sent_email.with_subject(/spam/).
    to('[email protected]') }

    it {should have_sent_email.to {@user.email} }
    it { should have_sent_email.reply_to([user, other]) }
    ```
  2. @steveclarke steveclarke revised this gist Apr 13, 2012. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions rspec-expectations.md
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,12 @@ RSpec Expectations
    Built-in matchers
    -----------------

    ```ruby
    have(n)
    have_at_least(n)
    have_at_most(n)
    ```

    ### Equivalence

    ```ruby
  3. @steveclarke steveclarke revised this gist Apr 13, 2012. 1 changed file with 45 additions and 0 deletions.
    45 changes: 45 additions & 0 deletions rspec-expectations.md
    Original file line number Diff line number Diff line change
    @@ -73,8 +73,53 @@ expect { ... }.to throw_symbol(:symbol, 'value')
    ```ruby
    actual.should be_xxx # passes if actual.xxx?
    actual.should have_xxx(:arg) # passes if actual.has_xxx?(:arg)

    {:a => "A"}.should have_key(:a) # => {:a => "A"}.has_key?(:a) | passes
    {:a => "A"}.should have_key(:b) # => {:a => "A"}.has_key?(:b) | fails
    ```

    ### Change
    ```ruby
    expect {
    team.add_player(player)
    }.to change(roster, :count)

    expect {
    team.add_player(player)
    }.to change(roster, :count).by(1)

    expect {
    team.add_player(player)
    }.to change(roster, :count).by_at_least(1)

    expect {
    team.add_player(player)
    }.to change(roster, :count).by_at_most(1)

    string = "string"
    expect {
    string.reverse!
    }.to change { string }.from("string").to("gnirts")

    expect {
    person.happy_birthday
    }.to change(person, :birthday).from(32).to(33)

    expect {
    employee.develop_great_new_social_networking_app
    }.to change(employee, :title).from("Mail Clerk").to("CEO")

    expect {
    doctor.leave_office
    }.to change(doctor, :sign).from(/is in/).to(/is out/)

    user = User.new(:type => "admin")
    expect {
    user.symbolize_type
    }.to change(user, :type).from(String).to(Symbol)
    ```


    ### Ranges (Ruby >= 1.9 only)

    ```ruby
  4. @steveclarke steveclarke revised this gist Apr 11, 2012. 2 changed files with 119 additions and 1 deletion.
    118 changes: 118 additions & 0 deletions capybara.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,118 @@
    Capybara
    =================

    Matchers
    --------

    ```ruby
    have_button(locator)

    have_checked_field(locator)

    have_css('p#foo', :count => 4)
    have_css('li', :text => 'Horse', :visible => true)

    have_field('Name', :with => 'Jonas')
    have_field('Email', :type => 'email')

    have_link(locator, options = {})

    have_select('Language', :selected => 'German')
    have_select('Language', :selected => ['English', 'German'])
    have_select('Language', :options => ['English', 'German', 'Spanish'])
    have_select('Language', :with_options => ['English', 'German'])

    have_selector('p#foo')
    have_selector(:xpath, './/p[@id="foo"]')
    have_selector(:foo)
    have_selector('p#foo', :count => 4)
    have_selector('li', :text => 'Horse', :visible => true)

    have_table('People', :rows => [['Jonas', '24'], ['Peter', '32']])

    have_text(content)
    have_content(content)

    have_unchecked_field?(locator)

    have_xpath('.//p[@id="foo"]')
    have_xpath('.//p[@id="foo"]', :count => 4)
    have_xpath('.//li', :text => 'Horse', :visible => true)
    ```


    Actions
    -------

    ```ruby
    attach_file(locator, path)
    page.attach_file(locator, '/path/to/file.png')

    check(locator)
    page.check('German')

    choose(locator)
    page.choose('Male')

    click_button(locator)
    click_link(locator)
    click_link_or_button(locator) (also: #click_on)

    fill_in(locator, options = {})
    page.fill_in 'Name', :with => 'Bob'

    select(value, options = {})
    page.select 'March', :from => 'Month'

    uncheck(locator)
    page.uncheck('German')

    unselect(value, options = {})
    page.unselect 'March', :from => 'Month'
    ```

    Session
    -------

    ```ruby
    current_host
    current_path
    current_url
    evaluate_script(script)
    execute_script(script)
    html
    reset! # (also: #cleanup!, #reset_session!)
    response_headers # Returns a hash of response headers.
    save_and_open_page
    save_page
    source # (also: #body)
    status_code
    visit(url)
    within(*args)
    within_fieldset(locator)
    within_frame(frame_id)
    within_table(locator)
    within_window(handle, &blk)
    ```

    Finders
    -------

    ```ruby
    all([kind], locator, options)
    all(:css, 'a#person_123')
    all(:xpath, '//a[@id="person_123"]')
    all("a#person_123")
    all('a', :text => 'Home')
    all('#menu li', :visible => true)

    find('#foo').find('.bar')
    find(:xpath, '//div[contains(., "bar")]')
    find('li', :text => 'Quox').click_link('Delete')

    find_button(locator)
    find_by_id(id)
    find_field(locator) # aka field_labeled
    find_link(locator)
    first([kind], locator, options)
    ```
    2 changes: 1 addition & 1 deletion shoulda-matchers.md
    Original file line number Diff line number Diff line change
    @@ -144,7 +144,7 @@ ActionMailer Matchers
    ---------------------

    ```ruby
    it { should have_sent_email.with_subject(/is spam$/) }
    it { should have_sent_email.with_subject(/is spam$/) }
    it { should have_sent_email.from('[email protected]') }
    it { should have_sent_email.with_body(/is spam\./) }
    it { should have_sent_email.to('[email protected]') }
  5. @steveclarke steveclarke revised this gist Apr 11, 2012. 1 changed file with 14 additions and 0 deletions.
    14 changes: 14 additions & 0 deletions rails-matchers.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,17 @@
    RSpec-Rails
    ===========


    Models
    ------

    ```ruby
    obj.should be_valid
    obj.should have(n).errors_on(:field)
    obj.errors.on(:field).should == "is required"
    ```


    General
    -------

    @@ -25,6 +36,7 @@ response.should render_template('same_controller/_a_partial')
    response.should render_template('other_controller/_a_partial')
    ```


    Routing
    -------

    @@ -38,6 +50,7 @@ Routing
    { :put => "path" }.should_not be_routable
    ```


    Content
    -------

    @@ -56,6 +69,7 @@ end
    response.should include_text("This text will be in the actual string")
    ```


    Mail
    ----

  6. @steveclarke steveclarke revised this gist Apr 10, 2012. 2 changed files with 118 additions and 39 deletions.
    39 changes: 0 additions & 39 deletions capybara-matchers.md
    Original file line number Diff line number Diff line change
    @@ -1,39 +0,0 @@
    Capybara Matchers
    =================


    ```ruby
    have_button(locator)

    have_checked_field(locator)

    have_css('p#foo', :count => 4)
    have_css('li', :text => 'Horse', :visible => true)

    have_field('Name', :with => 'Jonas')
    have_field('Email', :type => 'email')

    have_link(locator, options = {})

    have_select('Language', :selected => 'German')
    have_select('Language', :selected => ['English', 'German'])
    have_select('Language', :options => ['English', 'German', 'Spanish'])
    have_select('Language', :with_options => ['English', 'German'])

    have_selector('p#foo')
    have_selector(:xpath, './/p[@id="foo"]')
    have_selector(:foo)
    have_selector('p#foo', :count => 4)
    have_selector('li', :text => 'Horse', :visible => true)

    have_table('People', :rows => [['Jonas', '24'], ['Peter', '32']])

    have_text(content)
    have_content(content)

    have_unchecked_field?(locator)

    have_xpath('.//p[@id="foo"]')
    have_xpath('.//p[@id="foo"]', :count => 4)
    have_xpath('.//li', :text => 'Horse', :visible => true)
    ```
    118 changes: 118 additions & 0 deletions capybara.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,118 @@
    Capybara
    =================

    Matchers
    --------

    ```ruby
    have_button(locator)

    have_checked_field(locator)

    have_css('p#foo', :count => 4)
    have_css('li', :text => 'Horse', :visible => true)

    have_field('Name', :with => 'Jonas')
    have_field('Email', :type => 'email')

    have_link(locator, options = {})

    have_select('Language', :selected => 'German')
    have_select('Language', :selected => ['English', 'German'])
    have_select('Language', :options => ['English', 'German', 'Spanish'])
    have_select('Language', :with_options => ['English', 'German'])

    have_selector('p#foo')
    have_selector(:xpath, './/p[@id="foo"]')
    have_selector(:foo)
    have_selector('p#foo', :count => 4)
    have_selector('li', :text => 'Horse', :visible => true)

    have_table('People', :rows => [['Jonas', '24'], ['Peter', '32']])

    have_text(content)
    have_content(content)

    have_unchecked_field?(locator)

    have_xpath('.//p[@id="foo"]')
    have_xpath('.//p[@id="foo"]', :count => 4)
    have_xpath('.//li', :text => 'Horse', :visible => true)
    ```


    Actions
    -------

    ```ruby
    attach_file(locator, path)
    page.attach_file(locator, '/path/to/file.png')

    check(locator)
    page.check('German')

    choose(locator)
    page.choose('Male')

    click_button(locator)
    click_link(locator)
    click_link_or_button(locator) (also: #click_on)

    fill_in(locator, options = {})
    page.fill_in 'Name', :with => 'Bob'

    select(value, options = {})
    page.select 'March', :from => 'Month'

    uncheck(locator)
    page.uncheck('German')

    unselect(value, options = {})
    page.unselect 'March', :from => 'Month'
    ```

    Session
    -------

    ```ruby
    current_host
    current_path
    current_url
    evaluate_script(script)
    execute_script(script)
    html
    reset! # (also: #cleanup!, #reset_session!)
    response_headers # Returns a hash of response headers.
    save_and_open_page
    save_page
    source # (also: #body)
    status_code
    visit(url)
    within(*args)
    within_fieldset(locator)
    within_frame(frame_id)
    within_table(locator)
    within_window(handle, &blk)
    ```

    Finders
    -------

    ```ruby
    all([kind], locator, options)
    all(:css, 'a#person_123')
    all(:xpath, '//a[@id="person_123"]')
    all("a#person_123")
    all('a', :text => 'Home')
    all('#menu li', :visible => true)

    find('#foo').find('.bar')
    find(:xpath, '//div[contains(., "bar")]')
    find('li', :text => 'Quox').click_link('Delete')

    find_button(locator)
    find_by_id(id)
    find_field(locator) # aka field_labeled
    find_link(locator)
    first([kind], locator, options)
    ```
  7. @steveclarke steveclarke revised this gist Apr 10, 2012. 1 changed file with 39 additions and 0 deletions.
    39 changes: 39 additions & 0 deletions capybara-matchers.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,39 @@
    Capybara Matchers
    =================


    ```ruby
    have_button(locator)

    have_checked_field(locator)

    have_css('p#foo', :count => 4)
    have_css('li', :text => 'Horse', :visible => true)

    have_field('Name', :with => 'Jonas')
    have_field('Email', :type => 'email')

    have_link(locator, options = {})

    have_select('Language', :selected => 'German')
    have_select('Language', :selected => ['English', 'German'])
    have_select('Language', :options => ['English', 'German', 'Spanish'])
    have_select('Language', :with_options => ['English', 'German'])

    have_selector('p#foo')
    have_selector(:xpath, './/p[@id="foo"]')
    have_selector(:foo)
    have_selector('p#foo', :count => 4)
    have_selector('li', :text => 'Horse', :visible => true)

    have_table('People', :rows => [['Jonas', '24'], ['Peter', '32']])

    have_text(content)
    have_content(content)

    have_unchecked_field?(locator)

    have_xpath('.//p[@id="foo"]')
    have_xpath('.//p[@id="foo"]', :count => 4)
    have_xpath('.//li', :text => 'Horse', :visible => true)
    ```
  8. @steveclarke steveclarke revised this gist Apr 10, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion shoulda-matchers.md
    Original file line number Diff line number Diff line change
    @@ -144,7 +144,7 @@ ActionMailer Matchers
    ---------------------

    ```ruby
    it { should have_sent_email.with_subject(/is spam$/) }
    it { should have_sent_email.with_subject(/is spam$/) }
    it { should have_sent_email.from('[email protected]') }
    it { should have_sent_email.with_body(/is spam\./) }
    it { should have_sent_email.to('[email protected]') }
  9. @steveclarke steveclarke revised this gist Apr 10, 2012. 3 changed files with 19 additions and 15 deletions.
    15 changes: 11 additions & 4 deletions rails-matchers.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,8 @@
    ### General
    RSpec-Rails
    ===========

    General
    -------

    ```ruby
    response.should be_valid
    @@ -21,7 +25,8 @@ response.should render_template('same_controller/_a_partial')
    response.should render_template('other_controller/_a_partial')
    ```

    ### Routing
    Routing
    -------

    ```ruby
    "path".should route_to(expected) # assumes GET
    @@ -33,7 +38,8 @@ response.should render_template('other_controller/_a_partial')
    { :put => "path" }.should_not be_routable
    ```

    ### Content
    Content
    -------

    ```ruby
    response.should have_tag("div", "some text")
    @@ -50,7 +56,8 @@ end
    response.should include_text("This text will be in the actual string")
    ```

    ### Mail
    Mail
    ----

    ```ruby
    response.should send_email(*args, &block)
    8 changes: 6 additions & 2 deletions rspec-expectations.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,8 @@
    ## Built-in matchers
    RSpec Expectations
    ==================

    Built-in matchers
    -----------------

    ### Equivalence

    @@ -98,4 +102,4 @@ actual.should end_with(expected)
    "this string".should include("is str")
    "this string".should start_with("this")
    "this string".should end_with("ring")
    ```
    ```
    11 changes: 2 additions & 9 deletions shoulda-matchers.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    Shoulda Rails
    =============
    Shoulda
    =======

    ActiveRecord Matchers
    ---------------------
    @@ -156,10 +156,3 @@ it { should have_sent_email.with_subject(/spam/).

    it {should have_sent_email.to {@user.email} }
    ```

    Other
    -----

    ```ruby
    ```

  10. @steveclarke steveclarke revised this gist Apr 10, 2012. 1 changed file with 102 additions and 0 deletions.
    102 changes: 102 additions & 0 deletions shoulda-matchers.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,6 @@
    Shoulda Rails
    =============

    ActiveRecord Matchers
    ---------------------

    @@ -12,6 +15,25 @@ end
    describe User do
    it { should have_many(:posts) }
    end

    it { should have_and_belong_to_many(:posts) }

    it { should_not have_db_column(:admin).of_type(:boolean) }
    it { should have_db_column(:salary).
    of_type(:decimal).
    with_options(:precision => 10, :scale => 2) }

    it { should have_db_index(:age) }
    it { should have_db_index([:commentable_type, :commentable_id]) }
    it { should have_db_index(:ssn).unique(true) }

    it { should have_many(:friends) }
    it { should have_many(:enemies).through(:friends) }
    it { should have_many(:enemies).dependent(:destroy) }

    it { should have_one(:god) }

    it { should have_readonly_attribute(:password) }
    ```

    ActiveModel Matchers
    @@ -25,6 +47,16 @@ describe Post do
    it { should validate_presence_of(:body).with_message(/wtf/) }
    it { should validate_presence_of(:title) }
    it { should validate_numericality_of(:user_id) }
    it { should validate_acceptance_of(:eula) }

    it { should validate_format_of(:name).
    with('12345').
    with_message(/is not optional/) }
    it { should validate_format_of(:name).
    not_with('12D45').
    with_message(/is not optional/) }
    it { should validate_numericality_of(:age) }


    # validates_uniqueness_of requires an entry to be in the database already
    it "validates uniqueness of title" do
    @@ -37,8 +69,19 @@ describe User do
    it { should_not allow_value("blah").for(:email) }
    it { should allow_value("[email protected]").for(:email) }
    it { should ensure_inclusion_of(:age).in_range(1..100) }
    it { should ensure_exclusion_of(:age).in_range(30..60) }
    it { should_not allow_mass_assignment_of(:password) }
    end

    it { should ensure_length_of(:password).
    is_at_least(6).
    is_at_most(20) }
    it { should ensure_length_of(:name).
    is_at_least(3).
    with_short_message(/not long enough/) }
    it { should ensure_length_of(:ssn).
    is_equal_to(9).
    with_message(/is invalid/) }
    ```

    ActionController Matchers
    @@ -59,5 +102,64 @@ describe PostsController, "#show" do
    it { should_not set_the_flash }
    end
    end

    # other examples
    it { should assign_to(:user) }
    it { should_not assign_to(:user) }
    it { should assign_to(:user).with_kind_of(User) }
    it { should assign_to(:user).with(@user) }

    it { should render_with_layout }
    it { should render_with_layout(:special) }
    it { should_not render_with_layout }

    it { should respond_with(:success) }
    it { should respond_with(:redirect) }
    it { should respond_with(:missing) }
    it { should respond_with(:error) }
    it { should respond_with(501) }

    it { should respond_with_content_type(:xml) }
    it { should respond_with_content_type(:csv) }
    it { should respond_with_content_type(:atom) }
    it { should respond_with_content_type(:yaml) }
    it { should respond_with_content_type(:text) }
    it { should respond_with_content_type('application/rss+xml') }
    it { should respond_with_content_type(/json/) }

    it { should set_session(:message) }
    it { should set_session(:user_id).to(@user.id) }
    it { should_not set_session(:user_id) }

    it { should set_the_flash }
    it { should set_the_flash.to("Thank you for placing this order.") }
    it { should set_the_flash.to(/created/i) }
    it { should set_the_flash.to(/logged in/i).now }
    it { should_not set_the_flash }

    it { should filter_param(:password) }
    ```

    ActionMailer Matchers
    ---------------------

    ```ruby
    it { should have_sent_email.with_subject(/is spam$/) }
    it { should have_sent_email.from('[email protected]') }
    it { should have_sent_email.with_body(/is spam\./) }
    it { should have_sent_email.to('[email protected]') }
    it { should have_sent_email.with_part('text/html', /HTML spam/) }
    it { should have_sent_email.with_subject(/spam/).
    from('[email protected]').
    with_body(/spam/).
    to('[email protected]') }

    it {should have_sent_email.to {@user.email} }
    ```

    Other
    -----

    ```ruby
    ```

  11. @steveclarke steveclarke revised this gist Apr 10, 2012. 1 changed file with 50 additions and 41 deletions.
    91 changes: 50 additions & 41 deletions shoulda-matchers.md
    Original file line number Diff line number Diff line change
    @@ -1,54 +1,63 @@
    ## ActiveRecord Matchers
    ActiveRecord Matchers
    ---------------------

    Matchers to test associations:

    describe Post do
    it { should belong_to(:user) }
    it { should have_many(:tags).through(:taggings) }
    end
    ```ruby
    describe Post do
    it { should belong_to(:user) }
    it { should have_many(:tags).through(:taggings) }
    end

    describe User do
    it { should have_many(:posts) }
    end
    describe User do
    it { should have_many(:posts) }
    end
    ```

    ## ActiveModel Matchers
    ActiveModel Matchers
    --------------------

    Matchers to test validations and mass assignments:

    describe Post do
    it { should validate_uniqueness_of(:title) }
    it { should validate_presence_of(:body).with_message(/wtf/) }
    it { should validate_presence_of(:title) }
    it { should validate_numericality_of(:user_id) }

    # validates_uniqueness_of requires an entry to be in the database already
    it "validates uniqueness of title" do
    Post.create!(title: "My Awesome Post", body: "whatever")
    should validate_uniqueness_of(:title)
    end
    end

    describe User do
    it { should_not allow_value("blah").for(:email) }
    it { should allow_value("[email protected]").for(:email) }
    it { should ensure_inclusion_of(:age).in_range(1..100) }
    it { should_not allow_mass_assignment_of(:password) }
    end

    ## ActionController Matchers
    ```ruby
    describe Post do
    it { should validate_uniqueness_of(:title) }
    it { should validate_presence_of(:body).with_message(/wtf/) }
    it { should validate_presence_of(:title) }
    it { should validate_numericality_of(:user_id) }

    # validates_uniqueness_of requires an entry to be in the database already
    it "validates uniqueness of title" do
    Post.create!(title: "My Awesome Post", body: "whatever")
    should validate_uniqueness_of(:title)
    end
    end

    describe User do
    it { should_not allow_value("blah").for(:email) }
    it { should allow_value("[email protected]").for(:email) }
    it { should ensure_inclusion_of(:age).in_range(1..100) }
    it { should_not allow_mass_assignment_of(:password) }
    end
    ```

    ActionController Matchers
    -------------------------

    Matchers to test common patterns:

    describe PostsController, "#show" do
    context "for a fictional user" do
    before do
    get :show, :id => 1
    end

    it { should assign_to(:user) }
    it { should respond_with(:success) }
    it { should render_template(:show) }
    it { should_not set_the_flash }
    end
    ```ruby
    describe PostsController, "#show" do
    context "for a fictional user" do
    before do
    get :show, :id => 1
    end

    it { should assign_to(:user) }
    it { should respond_with(:success) }
    it { should render_template(:show) }
    it { should_not set_the_flash }
    end
    end
    ```

  12. @steveclarke steveclarke revised this gist Apr 10, 2012. 1 changed file with 54 additions and 0 deletions.
    54 changes: 54 additions & 0 deletions shoulda-matchers.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,54 @@
    ## ActiveRecord Matchers

    Matchers to test associations:

    describe Post do
    it { should belong_to(:user) }
    it { should have_many(:tags).through(:taggings) }
    end

    describe User do
    it { should have_many(:posts) }
    end

    ## ActiveModel Matchers

    Matchers to test validations and mass assignments:

    describe Post do
    it { should validate_uniqueness_of(:title) }
    it { should validate_presence_of(:body).with_message(/wtf/) }
    it { should validate_presence_of(:title) }
    it { should validate_numericality_of(:user_id) }

    # validates_uniqueness_of requires an entry to be in the database already
    it "validates uniqueness of title" do
    Post.create!(title: "My Awesome Post", body: "whatever")
    should validate_uniqueness_of(:title)
    end
    end

    describe User do
    it { should_not allow_value("blah").for(:email) }
    it { should allow_value("[email protected]").for(:email) }
    it { should ensure_inclusion_of(:age).in_range(1..100) }
    it { should_not allow_mass_assignment_of(:password) }
    end

    ## ActionController Matchers

    Matchers to test common patterns:

    describe PostsController, "#show" do
    context "for a fictional user" do
    before do
    get :show, :id => 1
    end

    it { should assign_to(:user) }
    it { should respond_with(:success) }
    it { should render_template(:show) }
    it { should_not set_the_flash }
    end
    end

  13. @steveclarke steveclarke revised this gist Apr 10, 2012. 1 changed file with 18 additions and 0 deletions.
    18 changes: 18 additions & 0 deletions paperclip-matchers.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    Paperclip with Shoulda
    ======================

    [docs](http://rubydoc.info/gems/paperclip/Paperclip/Shoulda/Matchers)

    ```ruby
    describe User do
    it { should have_attached_file(:avatar) }
    it { should validate_attachment_presence(:avatar) }
    it { should validate_attachment_content_type(:avatar).
    allowing('image/png', 'image/gif').
    rejecting('text/plain', 'text/xml') }
    it { should validate_attachment_size(:avatar).
    less_than(2.megabytes) }
    end
    ```


  14. @steveclarke steveclarke revised this gist Apr 10, 2012. 1 changed file with 53 additions and 5 deletions.
    58 changes: 53 additions & 5 deletions rails-matchers.md
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,58 @@
    ```ruby
    response.should redirect_to("some/url") #redirect_to(url) is the matcher.

    response.should be_success #passes if response.success?
    response.should be_redirect #passes if response.redirect?
    ### General

    ```ruby
    response.should be_valid
    response.should_not be_valid

    response.should be_success
    response.should be_redirect

    response.should redirect_to("path/to/action")
    response.should redirect_to("http://test.host/path/to/action")
    response.should redirect_to(:action => 'list')

    response.should render_template('list')
    response.should render_template('same_controller/list')
    response.should render_template('other_controller/list')

    # partials
    response.should render_template('_a_partial')
    response.should render_template('same_controller/_a_partial')
    response.should render_template('other_controller/_a_partial')
    ```

    ### Routing

    ```ruby
    "path".should route_to(expected) # assumes GET
    { :get => "path" }.should route_to(expected)
    { :put => "path" }.should route_to(expected)

    { "path" }.should_not be_routable # assumes GET
    { :get => "path" }.should_not be_routable
    { :put => "path" }.should_not be_routable
    ```

    ### Content

    ```ruby
    response.should have_tag("div", "some text")
    person_address_tag.should have_tag("input#person_address") # in a helper

    response.should have_tag("div#form") do
    with_tag("input#person_name[name=?]", "person[name]")
    end

    response.should have_tag("div#1") do
    without_tag("span", "some text that shouldn't be there")
    end

    response.should include_text("This text will be in the actual string")
    ```

    ### Mail

    ```ruby
    response.should send_email(*args, &block)
    ```

  15. @steveclarke steveclarke revised this gist Apr 10, 2012. 1 changed file with 10 additions and 0 deletions.
    10 changes: 10 additions & 0 deletions rails-matchers.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    ```ruby
    response.should redirect_to("some/url") #redirect_to(url) is the matcher.

    response.should be_success #passes if response.success?
    response.should be_redirect #passes if response.redirect?

    response.should be_valid
    response.should_not be_valid
    ```

  16. @steveclarke steveclarke revised this gist Apr 10, 2012. No changes.
  17. @steveclarke steveclarke renamed this gist Apr 10, 2012. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  18. @steveclarke steveclarke created this gist Apr 10, 2012.
    101 changes: 101 additions & 0 deletions rspec-expectations.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,101 @@
    ## Built-in matchers

    ### Equivalence

    ```ruby
    actual.should eq(expected) # passes if actual == expected
    actual.should == expected # passes if actual == expected
    actual.should eql(expected) # passes if actual.eql?(expected)
    ```

    ### Identity

    ```ruby
    actual.should be(expected) # passes if actual.equal?(expected)
    actual.should equal(expected) # passes if actual.equal?(expected)
    ```

    ### Comparisons

    ```ruby
    actual.should be > expected
    actual.should be >= expected
    actual.should be <= expected
    actual.should be < expected
    actual.should be_within(delta).of(expected)
    ```

    ### Regular expressions

    ```ruby
    actual.should =~ /expression/
    actual.should match(/expression/)
    ```

    ### Types/classes

    ```ruby
    actual.should be_an_instance_of(expected)
    actual.should be_a_kind_of(expected)
    ```

    ### Truthiness

    ```ruby
    actual.should be_true # passes if actual is truthy (not nil or false)
    actual.should be_false # passes if actual is falsy (nil or false)
    actual.should be_nil # passes if actual is nil
    ```

    ### Expecting errors

    ```ruby
    expect { ... }.to raise_error
    expect { ... }.to raise_error(ErrorClass)
    expect { ... }.to raise_error("message")
    expect { ... }.to raise_error(ErrorClass, "message")
    ```

    ### Expecting throws

    ```ruby
    expect { ... }.to throw_symbol
    expect { ... }.to throw_symbol(:symbol)
    expect { ... }.to throw_symbol(:symbol, 'value')
    ```

    ### Predicate matchers

    ```ruby
    actual.should be_xxx # passes if actual.xxx?
    actual.should have_xxx(:arg) # passes if actual.has_xxx?(:arg)
    ```

    ### Ranges (Ruby >= 1.9 only)

    ```ruby
    (1..10).should cover(3)
    ```

    ### Collection membership

    ```ruby
    actual.should include(expected)
    actual.should start_with(expected)
    actual.should end_with(expected)
    ```

    #### Examples

    ```ruby
    [1,2,3].should include(1)
    [1,2,3].should include(1, 2)
    [1,2,3].should start_with(1)
    [1,2,3].should start_with(1,2)
    [1,2,3].should end_with(3)
    [1,2,3].should end_with(2,3)
    {:a => 'b'}.should include(:a => 'b')
    "this string".should include("is str")
    "this string".should start_with("this")
    "this string".should end_with("ring")
    ```