4

EDIT: As per @max suggestion, I'm changing my model to use enum instead, however I can't test it for default state:

it { is_expected.to validate_inclusion_of(:status).to_allow("draft", "published") }

Works fine with the following code in the model:

validates :status,        :inclusion => { :in => ["draft", "published"] }

But this part still fails:

it { is_expected.to have_field(:status).with_default_value_of("draft") }

Please note that I'm using Mongoid. I have this in my model spec:

OLD question - kept for reference?

it { is_expected.to have_field(:published).of_type(Boolean).with_default_value_of(false) }

And in my model I have this:

field :published,         type: Mongoid::Boolean,     default: false

Yet is not working. I've tried removing the Mongoid bit but get the same error:

Failure/Error: it { is_expected.to have_field(:published).of_type(Boolean).with_default_value_of(false) } Expected Post to have field named "published" of type Boolean with default value of false, got field "published" of type Mongoid::Boolean

Note: I've also tried:

field :published,         type: Boolean,     default: false

And have added the following method in my model:

after_initialize :set_published, :if => :new_record?

then

private
def set_published
  self.published ||= false
end

But nothing seems to work. What am I missing?

WagnerMatosUK
  • 4,309
  • 7
  • 56
  • 95

2 Answers2

2
class Article
  include Mongoid::Document
  field :published, type: Boolean, default: false
end

require 'rails_helper'

RSpec.describe Article, type: :model do
  it { is_expected.to have_field(:published)
                      .of_type(Mongoid::Boolean)
                      .with_default_value_of(false) }
end

Passes perfectly fine on mongoid (4.0.2), mongoid-rspec (2.1.0).

But quite frankly using booleans for model state is sub-optimal.

If you consider a blog post or article it could be:

 1. draft
 2. published
 3. deleted
 4. ... 

Adding N number of switches in the model is icky - an awesome solution is to use Enums.

First write the spec:

RSpec.describe Article, type: :model do

  specify 'the default status of an article should be :draft' do
    expect(subject.status).to eq :draft
  end

  # or with rspec-its
  # its(:status) { should eq :draft }
end

Then add gem "mongoid-enum" to your Gemfile.

Finally add the enum field:

class Article
  include Mongoid::Document
  include Mongoid::Enum
  enum :status, [:draft, :published]
end

Enums add all this awesomeness:

Article.published # Scope to get all published articles
article.published? # Interrogation methods for each state.
article.published! # sets the status
max
  • 96,212
  • 14
  • 104
  • 165
  • Shoulda-matchers has a `it { should define_enum_for :status }` matcher for ActiveRecord enums but I don't know if anyring similar exists for Mongoid. – max Jul 08 '15 at 17:51
  • I see your point and have changed the code to use enum. Thanks for the suggestion! The only thing is I can't find how to test it for default state – WagnerMatosUK Jul 09 '15 at 06:07
  • 1
    The test above tests that the default state is draft. You could also do something like `expect(Article.new.draft?).to be_truthy` to avoid using subject explicitly. – max Jul 09 '15 at 11:26
  • That did the trick (`it { expect(Article.new.draft?).to be_truthy }`) Thanks! – WagnerMatosUK Jul 09 '15 at 12:41
2

If I understand correctly, you tried both Mongoid::Boolean and Boolean in your model, but not in the test.

Given the test failure message, I think it should be:

it { is_expected.to have_field(:published).of_type(Mongoid::Boolean).with_default_value_of(false) }

(and field :published, type: Mongoid::Boolean, default: false in your model)

Second problem:

Are you aware that have_field is to make tests on the views (the generated HTML), not to check that the field exists in the database?

We can't help you without the code of your views.

To check that the default value is draft, I'm not aware of any built-in Rails test method, so you should do it by hand. First create a new instance of your model, save it, and then check that the field published has draft value.

I'm not familiar with Rspec and the syntax you're using , but it should be something like (assuming you model is named Post):

before {
    @post = Post.new
    # some initialization code if needed
    @post.save
}
expect(@post.published).to be("draft")
vmarquet
  • 2,384
  • 3
  • 25
  • 39
  • hey @vmarquet, your answer was correct, however max suggestion seemed to have made more sense. Thanks for your help anyway! – WagnerMatosUK Jul 09 '15 at 06:12
  • I wasn't aware, no. I just need to test the whether the model with property `published` has a default value of `draft`. How would I go about that? PS: I'm still a newbie with Rspec and TDD. Thanks! – WagnerMatosUK Jul 09 '15 at 07:59