Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing that rails model validates date with RSpec

I'm a bit new to Rails and Rspec and as such I'm not sure how to test that date time validations are correct in my model. I've made a model Event that has start and end times and there's a few imporant conditions on these such as a start time cannot be in the past and the end time must be after the start time.

To ensure these validations I'm using ValidatesTimeliness https://github.com/adzap/validates_timeliness

My model is as follows:

class Event < ActiveRecord::Base
  ...

  validates_datetime :start_date,
    :after => :now,
    :after_message => "Event cannot start in the past"

  validates_datetime :end_date,
    :after => :start_date,
    :after_message => "End time cannot be before start time"
end

In my RSpec test I have:

describe Event do
  let(:event) { FactoryGirl.build :event }
  subject { event }

  context "when start_date is before the current time" do
    it {should_not allow_value(1.day.ago).
        for(:start_date)}
  end

  context "when end_date is before or on start date" do
    it {should_not allow_value(event.start_date - 1.day).
        for(:end_date)}

    it {should_not allow_value(event.start_date).
        for(:end_date)}
  end

  context "when the end_date is after the start_date" do
    it {should allow_value(event.start_date + 1.day).
        for(:end_date)}
  end
end

However this doesn't really test that my start date had to be before the exact date time. For example if I'd accidentally used :today instead of :now in my model, these tests would also pass.

I read online that there used to be an RSpec matcher called validate_date (http://www.railslodge.com/plugins/1160-validates-timeliness) which would be exactly what I'm looking for but as far as I can tell it's been removed.

My question is how can I improve my tests, do I need to add tests that try the smallest amount of time (i.e. a ms) to ensure the pass/fail accordingly or is there a better way to do it?

Thanks in advance!

like image 412
Sarah Tattersall Avatar asked Oct 30 '12 11:10

Sarah Tattersall


2 Answers

You could work with valid? and errors.messages:

  • Build anEvent that passes validation except for your start_date and end_date
  • Set the start_date and end_date in the right order, and assert that event.valid? is true
  • Set the start_date and end_date in the wrong order, and assert that it is not valid? and that event.errors.messages includes the right validation errors. (Note, you have to call event.valid? before checking event.errors.messages, otherwise they will be empty)

Example for valid? and errors.messages:

 user = User.new
 user.errors.messages #=> {} # no messages, since validations never ran
 user.valid? # => false
 user.errors.messages #=> {:email=>["can't be blank"]}

 user.email = "[email protected]"
 user.valid? #=> true
 user.errors.messages #=> {}
like image 59
doesterr Avatar answered Sep 30 '22 10:09

doesterr


Try this

validates_date :end_time, :after => [:start_time, Proc.new {1.day.from_now_to_date}]
validates_date :start_time, :after => Time.now
like image 32
Aggelos Avgerinos Avatar answered Sep 30 '22 10:09

Aggelos Avgerinos