2016-03-05 17:07:32 -05:00
|
|
|
require "rails_helper"
|
2013-08-27 16:34:16 -04:00
|
|
|
|
2016-02-15 22:32:40 -05:00
|
|
|
describe Widget, type: :model do
|
2016-03-05 17:07:32 -05:00
|
|
|
describe "`be_versioned` matcher" do
|
2014-10-31 10:40:43 -04:00
|
|
|
it { is_expected.to be_versioned }
|
2013-10-29 12:07:54 -04:00
|
|
|
end
|
|
|
|
|
2016-03-05 17:07:32 -05:00
|
|
|
let(:widget) { Widget.create! name: "Bob", an_integer: 1 }
|
2013-10-29 12:07:54 -04:00
|
|
|
|
2016-03-05 17:07:32 -05:00
|
|
|
describe "`have_a_version_with` matcher", versioning: true do
|
2014-07-09 08:47:15 -04:00
|
|
|
before do
|
2016-03-05 17:11:08 -05:00
|
|
|
widget.update_attributes!(name: "Leonard", an_integer: 1)
|
2016-03-05 17:07:32 -05:00
|
|
|
widget.update_attributes!(name: "Tom")
|
|
|
|
widget.update_attributes!(name: "Bob")
|
2014-07-09 08:47:15 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is possible to do assertions on versions" do
|
2016-03-13 19:59:24 -04:00
|
|
|
expect(widget).to have_a_version_with name: "Leonard", an_integer: 1
|
|
|
|
expect(widget).to have_a_version_with an_integer: 1
|
|
|
|
expect(widget).to have_a_version_with name: "Tom"
|
2014-07-09 08:47:15 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-02-15 18:27:57 -05:00
|
|
|
describe "versioning option" do
|
2016-02-15 22:32:40 -05:00
|
|
|
context "enabled", versioning: true do
|
2016-02-15 18:27:57 -05:00
|
|
|
it "should enable versioning" do
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(widget.versions.size).to eq(1)
|
2013-10-29 12:07:54 -04:00
|
|
|
end
|
|
|
|
end
|
2013-08-27 16:34:16 -04:00
|
|
|
|
2016-02-15 18:27:57 -05:00
|
|
|
context "disabled (default)" do
|
|
|
|
it "should not enable versioning" do
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(widget.versions.size).to eq(0)
|
2013-10-29 12:07:54 -04:00
|
|
|
end
|
2013-08-27 16:34:16 -04:00
|
|
|
end
|
|
|
|
end
|
2014-02-12 18:27:10 -05:00
|
|
|
|
2016-02-15 22:32:40 -05:00
|
|
|
describe "Callbacks", versioning: true do
|
2014-04-16 16:33:10 -04:00
|
|
|
describe :before_save do
|
2016-03-05 17:07:32 -05:00
|
|
|
context ":on => :update" do
|
|
|
|
before { widget.update_attributes!(name: "Foobar") }
|
2014-04-16 16:33:10 -04:00
|
|
|
|
|
|
|
subject { widget.versions.last.reify }
|
|
|
|
|
2016-02-15 18:27:57 -05:00
|
|
|
it "resets value for timestamp attrs for update so that value gets updated properly" do
|
2016-01-11 22:07:57 -05:00
|
|
|
# Travel 1 second because MySQL lacks sub-second resolution
|
|
|
|
Timecop.travel(1) do
|
|
|
|
expect { subject.save! }.to change(subject, :updated_at)
|
|
|
|
end
|
2014-04-16 16:33:10 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-07-30 16:17:02 -04:00
|
|
|
describe :after_create do
|
2016-03-05 17:07:32 -05:00
|
|
|
let(:widget) { Widget.create!(name: "Foobar", created_at: Time.now - 1.week) }
|
2014-07-30 16:17:02 -04:00
|
|
|
|
2015-08-11 21:37:50 -04:00
|
|
|
it "corresponding version should use the widget's `updated_at`" do
|
|
|
|
expect(widget.versions.last.created_at.to_i).to eq(widget.updated_at.to_i)
|
2014-07-30 16:17:02 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-04-16 12:44:21 -04:00
|
|
|
describe :after_update do
|
2016-03-05 17:07:32 -05:00
|
|
|
before { widget.update_attributes!(name: "Foobar", updated_at: Time.now + 1.week) }
|
2014-04-16 12:44:21 -04:00
|
|
|
|
|
|
|
subject { widget.versions.last.reify }
|
|
|
|
|
2016-02-23 17:59:14 -05:00
|
|
|
it { expect(subject.paper_trail).not_to be_live }
|
2014-04-16 12:44:21 -04:00
|
|
|
|
|
|
|
it "should clear the `versions_association_name` virtual attribute" do
|
|
|
|
subject.save!
|
2016-02-23 17:59:14 -05:00
|
|
|
expect(subject.paper_trail).to be_live
|
2014-04-16 12:44:21 -04:00
|
|
|
end
|
2014-05-30 17:38:23 -04:00
|
|
|
|
2014-07-30 16:17:02 -04:00
|
|
|
it "corresponding version should use the widget updated_at" do
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(widget.versions.last.created_at.to_i).to eq(widget.updated_at.to_i)
|
2014-05-30 17:38:23 -04:00
|
|
|
end
|
2014-04-16 12:44:21 -04:00
|
|
|
end
|
|
|
|
|
2014-04-16 12:17:33 -04:00
|
|
|
describe :after_destroy do
|
|
|
|
it "should create a version for that event" do
|
|
|
|
expect { widget.destroy }.to change(widget.versions, :count).by(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should assign the version into the `versions_association_name`" do
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(widget.version).to be_nil
|
2014-04-16 12:17:33 -04:00
|
|
|
widget.destroy
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(widget.version).not_to be_nil
|
|
|
|
expect(widget.version).to eq(widget.versions.last)
|
2014-04-16 12:17:33 -04:00
|
|
|
end
|
|
|
|
end
|
2014-11-10 19:12:50 -05:00
|
|
|
|
|
|
|
describe :after_rollback do
|
2016-03-05 17:07:32 -05:00
|
|
|
let(:rolled_back_name) { "Big Moo" }
|
2014-11-10 19:12:50 -05:00
|
|
|
|
|
|
|
before do
|
2014-11-10 19:20:57 -05:00
|
|
|
begin
|
|
|
|
widget.transaction do
|
2016-02-15 22:32:40 -05:00
|
|
|
widget.update_attributes!(name: rolled_back_name)
|
|
|
|
widget.update_attributes!(name: Widget::EXCLUDED_NAME)
|
2014-11-10 19:20:57 -05:00
|
|
|
end
|
|
|
|
rescue ActiveRecord::RecordInvalid
|
2014-11-10 20:32:54 -05:00
|
|
|
widget.reload
|
2014-11-10 19:20:57 -05:00
|
|
|
widget.name = nil
|
|
|
|
widget.save
|
2014-11-10 19:12:50 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-05 17:07:32 -05:00
|
|
|
it "does not create an event for changes that did not happen" do
|
2014-11-10 19:12:50 -05:00
|
|
|
widget.versions.map(&:changeset).each do |changeset|
|
2016-03-05 17:07:32 -05:00
|
|
|
expect(changeset.fetch("name", [])).to_not include(rolled_back_name)
|
2014-11-10 19:12:50 -05:00
|
|
|
end
|
|
|
|
end
|
2016-03-06 14:05:21 -05:00
|
|
|
|
|
|
|
it "has not yet loaded the assocation" do
|
|
|
|
expect(widget.versions).to_not be_loaded
|
|
|
|
end
|
2014-11-10 19:12:50 -05:00
|
|
|
end
|
2014-04-16 12:17:33 -04:00
|
|
|
end
|
|
|
|
|
2016-02-15 22:32:40 -05:00
|
|
|
describe "Association", versioning: true do
|
2014-06-03 16:26:53 -04:00
|
|
|
describe "sort order" do
|
|
|
|
it "should sort by the timestamp order from the `VersionConcern`" do
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(widget.versions.to_sql).to eq(
|
2016-05-15 03:14:36 -04:00
|
|
|
widget.versions.reorder(PaperTrail::Version.timestamp_sort_order).to_sql
|
|
|
|
)
|
2014-06-03 16:26:53 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-31 05:03:06 -04:00
|
|
|
if defined?(ActiveRecord::IdentityMap) && ActiveRecord::IdentityMap.respond_to?(:without)
|
|
|
|
describe "IdentityMap", versioning: true do
|
|
|
|
it "should not clobber the IdentityMap when reifying" do
|
|
|
|
widget.update_attributes name: "Henry", created_at: Time.now - 1.day
|
|
|
|
widget.update_attributes name: "Harry"
|
|
|
|
expect(ActiveRecord::IdentityMap).to receive(:without).once
|
|
|
|
widget.versions.last.reify
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-02-21 18:20:40 -05:00
|
|
|
describe "Methods" do
|
2016-02-15 22:32:40 -05:00
|
|
|
describe "Instance", versioning: true do
|
2016-06-27 03:02:33 -04:00
|
|
|
describe "#paper_trail.originator" do
|
2014-06-17 10:58:53 -04:00
|
|
|
describe "return value" do
|
2015-12-19 19:01:58 -05:00
|
|
|
let(:orig_name) { FFaker::Name.name }
|
|
|
|
let(:new_name) { FFaker::Name.name }
|
2014-06-17 10:58:53 -04:00
|
|
|
before { PaperTrail.whodunnit = orig_name }
|
|
|
|
|
|
|
|
context "accessed from live model instance" do
|
2016-02-23 17:59:14 -05:00
|
|
|
specify { expect(widget.paper_trail).to be_live }
|
2014-06-17 10:58:53 -04:00
|
|
|
|
|
|
|
it "should return the originator for the model at a given state" do
|
2016-02-23 17:59:14 -05:00
|
|
|
expect(widget.paper_trail.originator).to eq(orig_name)
|
|
|
|
widget.paper_trail.whodunnit(new_name) { |w|
|
|
|
|
w.update_attributes(name: "Elizabeth")
|
|
|
|
}
|
|
|
|
expect(widget.paper_trail.originator).to eq(new_name)
|
2014-06-17 10:58:53 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "accessed from a reified model instance" do
|
|
|
|
before do
|
2016-03-05 17:07:32 -05:00
|
|
|
widget.update_attributes(name: "Andy")
|
2014-06-17 10:58:53 -04:00
|
|
|
PaperTrail.whodunnit = new_name
|
2016-03-05 17:07:32 -05:00
|
|
|
widget.update_attributes(name: "Elizabeth")
|
2014-06-17 10:58:53 -04:00
|
|
|
end
|
|
|
|
|
2014-07-25 15:49:39 -04:00
|
|
|
context "default behavior (no `options[:dup]` option passed in)" do
|
2014-07-18 04:47:21 -04:00
|
|
|
let(:reified_widget) { widget.versions[1].reify }
|
|
|
|
|
|
|
|
it "should return the appropriate originator" do
|
2016-02-23 17:59:14 -05:00
|
|
|
expect(reified_widget.paper_trail.originator).to eq(orig_name)
|
2014-07-18 04:47:21 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should not create a new model instance" do
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(reified_widget).not_to be_new_record
|
2014-07-18 04:47:21 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-07-25 15:49:39 -04:00
|
|
|
context "creating a new instance (`options[:dup] == true`)" do
|
2016-02-15 22:32:40 -05:00
|
|
|
let(:reified_widget) { widget.versions[1].reify(dup: true) }
|
2014-07-18 04:47:21 -04:00
|
|
|
|
|
|
|
it "should return the appropriate originator" do
|
2016-02-23 17:59:14 -05:00
|
|
|
expect(reified_widget.paper_trail.originator).to eq(orig_name)
|
2014-07-18 04:47:21 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should not create a new model instance" do
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(reified_widget).to be_new_record
|
2014-07-18 04:47:21 -04:00
|
|
|
end
|
2014-06-17 10:58:53 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-06-27 03:02:33 -04:00
|
|
|
describe "#version_at" do
|
2014-06-18 11:01:38 -04:00
|
|
|
context "Timestamp argument is AFTER object has been destroyed" do
|
2016-02-23 17:59:14 -05:00
|
|
|
it "should return `nil`" do
|
2016-03-05 17:07:32 -05:00
|
|
|
widget.update_attribute(:name, "foobar")
|
2014-06-18 11:01:38 -04:00
|
|
|
widget.destroy
|
2016-02-23 17:59:14 -05:00
|
|
|
expect(widget.paper_trail.version_at(Time.now)).to be_nil
|
2014-06-18 11:01:38 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-06-27 03:02:33 -04:00
|
|
|
describe "#whodunnit" do
|
2014-10-09 15:04:17 -04:00
|
|
|
it { is_expected.to respond_to(:whodunnit) }
|
2014-03-11 17:55:44 -04:00
|
|
|
|
|
|
|
context "no block given" do
|
|
|
|
it "should raise an error" do
|
2016-02-15 18:27:57 -05:00
|
|
|
expect {
|
2016-02-23 17:59:14 -05:00
|
|
|
widget.paper_trail.whodunnit("Ben")
|
2016-03-05 17:07:32 -05:00
|
|
|
}.to raise_error(ArgumentError, "expected to receive a block")
|
2014-03-11 17:55:44 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "block given" do
|
2015-12-19 19:01:58 -05:00
|
|
|
let(:orig_name) { FFaker::Name.name }
|
|
|
|
let(:new_name) { FFaker::Name.name }
|
2014-03-11 17:55:44 -04:00
|
|
|
|
|
|
|
before do
|
|
|
|
PaperTrail.whodunnit = orig_name
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(widget.versions.last.whodunnit).to eq(orig_name) # persist `widget`
|
2014-03-11 17:55:44 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should modify value of `PaperTrail.whodunnit` while executing the block" do
|
2016-02-23 17:59:14 -05:00
|
|
|
widget.paper_trail.whodunnit(new_name) do
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(PaperTrail.whodunnit).to eq(new_name)
|
2016-03-05 17:07:32 -05:00
|
|
|
widget.update_attributes(name: "Elizabeth")
|
2014-03-11 17:55:44 -04:00
|
|
|
end
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(widget.versions.last.whodunnit).to eq(new_name)
|
2014-03-11 17:55:44 -04:00
|
|
|
end
|
|
|
|
|
2016-02-15 18:27:57 -05:00
|
|
|
context "after executing the block" do
|
|
|
|
it "reverts value of whodunnit to previous value" do
|
2016-02-23 17:59:14 -05:00
|
|
|
widget.paper_trail.whodunnit(new_name) { |w|
|
|
|
|
w.update_attributes(name: "Elizabeth")
|
|
|
|
}
|
2016-02-15 18:27:57 -05:00
|
|
|
expect(PaperTrail.whodunnit).to eq(orig_name)
|
|
|
|
end
|
2014-03-11 17:55:44 -04:00
|
|
|
end
|
2014-03-12 10:09:59 -04:00
|
|
|
|
|
|
|
context "error within block" do
|
2016-02-15 18:27:57 -05:00
|
|
|
it "still reverts the whodunnit value to previous value" do
|
2015-12-19 18:47:13 -05:00
|
|
|
expect {
|
2016-02-23 17:59:14 -05:00
|
|
|
widget.paper_trail.whodunnit(new_name) { raise }
|
2015-12-19 18:47:13 -05:00
|
|
|
}.to raise_error(RuntimeError)
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(PaperTrail.whodunnit).to eq(orig_name)
|
2014-03-12 10:09:59 -04:00
|
|
|
end
|
|
|
|
end
|
2014-03-11 17:55:44 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-06-27 03:02:33 -04:00
|
|
|
describe "#touch_with_version" do
|
2015-07-08 23:21:44 -04:00
|
|
|
it "creates a version" do
|
2014-02-21 18:20:40 -05:00
|
|
|
count = widget.versions.size
|
2016-01-11 22:07:57 -05:00
|
|
|
# Travel 1 second because MySQL lacks sub-second resolution
|
|
|
|
Timecop.travel(1) do
|
2016-02-23 17:59:14 -05:00
|
|
|
widget.paper_trail.touch_with_version
|
2016-01-11 22:07:57 -05:00
|
|
|
end
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(widget.versions.size).to eq(count + 1)
|
2014-02-21 18:20:40 -05:00
|
|
|
end
|
|
|
|
|
2015-07-08 23:21:44 -04:00
|
|
|
it "increments the `:updated_at` timestamp" do
|
2014-02-21 18:20:40 -05:00
|
|
|
time_was = widget.updated_at
|
2016-01-11 22:07:57 -05:00
|
|
|
# Travel 1 second because MySQL lacks sub-second resolution
|
|
|
|
Timecop.travel(1) do
|
2016-02-23 17:59:14 -05:00
|
|
|
widget.paper_trail.touch_with_version
|
2016-01-11 22:07:57 -05:00
|
|
|
end
|
2014-10-09 15:04:17 -04:00
|
|
|
expect(widget.updated_at).to be > time_was
|
2014-02-21 18:20:40 -05:00
|
|
|
end
|
2014-02-12 18:27:10 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-02-21 18:20:40 -05:00
|
|
|
describe "Class" do
|
2016-02-23 17:59:14 -05:00
|
|
|
describe ".paper_trail.enabled?" do
|
|
|
|
it "returns true" do
|
|
|
|
expect(Widget.paper_trail.enabled?).to eq(true)
|
|
|
|
end
|
2014-10-31 10:40:43 -04:00
|
|
|
end
|
|
|
|
|
2016-02-23 17:59:14 -05:00
|
|
|
describe ".disable" do
|
|
|
|
it "should set the `paper_trail.enabled?` to `false`" do
|
|
|
|
expect(Widget.paper_trail.enabled?).to eq(true)
|
|
|
|
Widget.paper_trail.disable
|
|
|
|
expect(Widget.paper_trail.enabled?).to eq(false)
|
2014-02-21 18:20:40 -05:00
|
|
|
end
|
2014-02-12 18:27:10 -05:00
|
|
|
end
|
|
|
|
|
2016-02-23 17:59:14 -05:00
|
|
|
describe ".enable" do
|
|
|
|
it "should set the `paper_trail.enabled?` to `true`" do
|
|
|
|
Widget.paper_trail.disable
|
|
|
|
expect(Widget.paper_trail.enabled?).to eq(false)
|
|
|
|
Widget.paper_trail.enable
|
|
|
|
expect(Widget.paper_trail.enabled?).to eq(true)
|
2014-02-21 18:20:40 -05:00
|
|
|
end
|
2014-02-12 18:27:10 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2013-08-27 16:34:16 -04:00
|
|
|
end
|