2017-12-11 04:05:11 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-05-30 04:58:26 +00:00
|
|
|
require "spec_helper"
|
2013-08-27 20:34:16 +00:00
|
|
|
|
2017-05-21 05:41:20 +00:00
|
|
|
RSpec.describe Widget, type: :model do
|
2017-09-19 03:56:07 +00:00
|
|
|
let(:widget) { Widget.create! name: "Bob", an_integer: 1 }
|
|
|
|
|
2016-03-05 22:07:32 +00:00
|
|
|
describe "`be_versioned` matcher" do
|
2014-10-31 14:40:43 +00:00
|
|
|
it { is_expected.to be_versioned }
|
2013-10-29 16:07:54 +00:00
|
|
|
end
|
|
|
|
|
2016-03-05 22:07:32 +00:00
|
|
|
describe "`have_a_version_with` matcher", versioning: true do
|
2014-07-09 12:47:15 +00:00
|
|
|
before do
|
2018-12-04 21:10:35 +00:00
|
|
|
widget.update!(name: "Leonard", an_integer: 1)
|
|
|
|
widget.update!(name: "Tom")
|
|
|
|
widget.update!(name: "Bob")
|
2014-07-09 12:47:15 +00:00
|
|
|
end
|
|
|
|
|
2016-11-01 05:14:52 +00:00
|
|
|
it "is possible to do assertions on version attributes" do
|
2016-03-13 23:59:24 +00: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 12:47:15 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-02-15 23:27:57 +00:00
|
|
|
describe "versioning option" do
|
2016-02-16 03:32:40 +00:00
|
|
|
context "enabled", versioning: true do
|
2017-04-01 05:50:13 +00:00
|
|
|
it "enables versioning" do
|
2014-10-09 19:04:17 +00:00
|
|
|
expect(widget.versions.size).to eq(1)
|
2013-10-29 16:07:54 +00:00
|
|
|
end
|
|
|
|
end
|
2013-08-27 20:34:16 +00:00
|
|
|
|
2016-02-15 23:27:57 +00:00
|
|
|
context "disabled (default)" do
|
2017-04-01 05:50:13 +00:00
|
|
|
it "does not enable versioning" do
|
2014-10-09 19:04:17 +00:00
|
|
|
expect(widget.versions.size).to eq(0)
|
2013-10-29 16:07:54 +00:00
|
|
|
end
|
2013-08-27 20:34:16 +00:00
|
|
|
end
|
|
|
|
end
|
2014-02-12 23:27:10 +00:00
|
|
|
|
2016-02-16 03:32:40 +00:00
|
|
|
describe "Callbacks", versioning: true do
|
2017-04-01 01:42:14 +00:00
|
|
|
describe "before_save" do
|
2017-04-01 06:28:55 +00:00
|
|
|
it "resets value for timestamp attrs for update so that value gets updated properly" do
|
2018-12-04 21:10:35 +00:00
|
|
|
widget.update!(name: "Foobar")
|
2017-10-27 16:07:47 +00:00
|
|
|
w = widget.versions.last.reify
|
2018-05-15 02:31:12 +00:00
|
|
|
expect { w.save! }.to change(w, :updated_at)
|
2014-04-16 20:33:10 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-04-01 01:42:14 +00:00
|
|
|
describe "after_create" do
|
2016-03-05 22:07:32 +00:00
|
|
|
let(:widget) { Widget.create!(name: "Foobar", created_at: Time.now - 1.week) }
|
2014-07-30 20:17:02 +00:00
|
|
|
|
2017-04-01 05:50:13 +00:00
|
|
|
it "corresponding version uses the widget's `updated_at`" do
|
2015-08-12 01:37:50 +00:00
|
|
|
expect(widget.versions.last.created_at.to_i).to eq(widget.updated_at.to_i)
|
2014-07-30 20:17:02 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-04-01 01:42:14 +00:00
|
|
|
describe "after_update" do
|
2017-10-27 16:07:47 +00:00
|
|
|
before do
|
2018-12-04 21:10:35 +00:00
|
|
|
widget.update!(name: "Foobar", updated_at: Time.now + 1.week)
|
2017-10-27 16:07:47 +00:00
|
|
|
end
|
2014-04-16 16:44:21 +00:00
|
|
|
|
2017-04-01 05:50:13 +00:00
|
|
|
it "clears the `versions_association_name` virtual attribute" do
|
2017-10-27 16:07:47 +00:00
|
|
|
w = widget.versions.last.reify
|
|
|
|
expect(w.paper_trail).not_to be_live
|
|
|
|
w.save!
|
|
|
|
expect(w.paper_trail).to be_live
|
2014-04-16 16:44:21 +00:00
|
|
|
end
|
2014-05-30 21:38:23 +00:00
|
|
|
|
2017-04-01 05:50:13 +00:00
|
|
|
it "corresponding version uses the widget updated_at" do
|
2014-10-09 19:04:17 +00:00
|
|
|
expect(widget.versions.last.created_at.to_i).to eq(widget.updated_at.to_i)
|
2014-05-30 21:38:23 +00:00
|
|
|
end
|
2014-04-16 16:44:21 +00:00
|
|
|
end
|
|
|
|
|
2017-04-01 01:42:14 +00:00
|
|
|
describe "after_destroy" do
|
2017-04-01 05:50:13 +00:00
|
|
|
it "creates a version for that event" do
|
2014-04-16 16:17:33 +00:00
|
|
|
expect { widget.destroy }.to change(widget.versions, :count).by(1)
|
|
|
|
end
|
|
|
|
|
2017-04-01 05:50:13 +00:00
|
|
|
it "assigns the version into the `versions_association_name`" do
|
2014-10-09 19:04:17 +00:00
|
|
|
expect(widget.version).to be_nil
|
2014-04-16 16:17:33 +00:00
|
|
|
widget.destroy
|
2014-10-09 19:04:17 +00:00
|
|
|
expect(widget.version).not_to be_nil
|
|
|
|
expect(widget.version).to eq(widget.versions.last)
|
2014-04-16 16:17:33 +00:00
|
|
|
end
|
|
|
|
end
|
2014-11-11 00:12:50 +00:00
|
|
|
|
2017-04-01 01:42:14 +00:00
|
|
|
describe "after_rollback" do
|
2016-03-05 22:07:32 +00:00
|
|
|
let(:rolled_back_name) { "Big Moo" }
|
2014-11-11 00:12:50 +00:00
|
|
|
|
|
|
|
before do
|
2014-11-11 00:20:57 +00:00
|
|
|
begin
|
|
|
|
widget.transaction do
|
2018-12-04 21:10:35 +00:00
|
|
|
widget.update!(name: rolled_back_name)
|
|
|
|
widget.update!(name: Widget::EXCLUDED_NAME)
|
2014-11-11 00:20:57 +00:00
|
|
|
end
|
|
|
|
rescue ActiveRecord::RecordInvalid
|
2014-11-11 01:32:54 +00:00
|
|
|
widget.reload
|
2014-11-11 00:20:57 +00:00
|
|
|
widget.name = nil
|
|
|
|
widget.save
|
2014-11-11 00:12:50 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-05 22:07:32 +00:00
|
|
|
it "does not create an event for changes that did not happen" do
|
2014-11-11 00:12:50 +00:00
|
|
|
widget.versions.map(&:changeset).each do |changeset|
|
2017-04-01 05:59:47 +00:00
|
|
|
expect(changeset.fetch("name", [])).not_to include(rolled_back_name)
|
2014-11-11 00:12:50 +00:00
|
|
|
end
|
|
|
|
end
|
2016-03-06 19:05:21 +00:00
|
|
|
|
|
|
|
it "has not yet loaded the assocation" do
|
2017-04-01 05:59:47 +00:00
|
|
|
expect(widget.versions).not_to be_loaded
|
2016-03-06 19:05:21 +00:00
|
|
|
end
|
2014-11-11 00:12:50 +00:00
|
|
|
end
|
2014-04-16 16:17:33 +00:00
|
|
|
end
|
|
|
|
|
2016-02-16 03:32:40 +00:00
|
|
|
describe "Association", versioning: true do
|
2014-06-03 20:26:53 +00:00
|
|
|
describe "sort order" do
|
2017-04-01 05:50:13 +00:00
|
|
|
it "sorts by the timestamp order from the `VersionConcern`" do
|
2014-10-09 19:04:17 +00:00
|
|
|
expect(widget.versions.to_sql).to eq(
|
2016-05-15 07:14:36 +00:00
|
|
|
widget.versions.reorder(PaperTrail::Version.timestamp_sort_order).to_sql
|
|
|
|
)
|
2014-06-03 20:26:53 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-31 09:03:06 +00:00
|
|
|
if defined?(ActiveRecord::IdentityMap) && ActiveRecord::IdentityMap.respond_to?(:without)
|
|
|
|
describe "IdentityMap", versioning: true do
|
2017-04-01 05:50:13 +00:00
|
|
|
it "does not clobber the IdentityMap when reifying" do
|
2018-12-04 21:10:35 +00:00
|
|
|
widget.update name: "Henry", created_at: Time.now - 1.day
|
|
|
|
widget.update name: "Harry"
|
2017-09-19 03:56:07 +00:00
|
|
|
allow(ActiveRecord::IdentityMap).to receive(:without)
|
2016-03-31 09:03:06 +00:00
|
|
|
widget.versions.last.reify
|
2017-09-19 03:56:07 +00:00
|
|
|
expect(ActiveRecord::IdentityMap).to have_receive(:without).once
|
2016-03-31 09:03:06 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-04-01 06:28:55 +00:00
|
|
|
describe "#create", versioning: true do
|
|
|
|
it "creates a version record" do
|
|
|
|
wordget = Widget.create
|
|
|
|
assert_equal 1, wordget.versions.length
|
|
|
|
end
|
|
|
|
end
|
2014-07-18 08:47:21 +00:00
|
|
|
|
2017-04-01 06:28:55 +00:00
|
|
|
describe "#destroy", versioning: true do
|
|
|
|
it "creates a version record" do
|
|
|
|
widget = Widget.create
|
|
|
|
assert_equal 1, widget.versions.length
|
|
|
|
widget.destroy
|
|
|
|
versions_for_widget = PaperTrail::Version.with_item_keys("Widget", widget.id)
|
|
|
|
assert_equal 2, versions_for_widget.length
|
|
|
|
end
|
2014-07-18 08:47:21 +00:00
|
|
|
|
2017-04-01 06:28:55 +00:00
|
|
|
it "can have multiple destruction records" do
|
|
|
|
versions = lambda { |widget|
|
|
|
|
# Workaround for AR 3. When we drop AR 3 support, we can simply use
|
|
|
|
# the `widget.versions` association, instead of `with_item_keys`.
|
|
|
|
PaperTrail::Version.with_item_keys("Widget", widget.id)
|
|
|
|
}
|
|
|
|
widget = Widget.create
|
|
|
|
assert_equal 1, widget.versions.length
|
|
|
|
widget.destroy
|
|
|
|
assert_equal 2, versions.call(widget).length
|
|
|
|
widget = widget.version.reify
|
|
|
|
widget.save
|
|
|
|
assert_equal 3, versions.call(widget).length
|
|
|
|
widget.destroy
|
|
|
|
assert_equal 4, versions.call(widget).length
|
|
|
|
assert_equal 2, versions.call(widget).where(event: "destroy").length
|
|
|
|
end
|
|
|
|
end
|
2014-07-18 08:47:21 +00:00
|
|
|
|
2017-04-01 06:28:55 +00:00
|
|
|
describe "#paper_trail.originator", versioning: true do
|
|
|
|
describe "return value" do
|
|
|
|
let(:orig_name) { FFaker::Name.name }
|
|
|
|
let(:new_name) { FFaker::Name.name }
|
2014-07-18 08:47:21 +00:00
|
|
|
|
2017-04-01 06:28:55 +00:00
|
|
|
before do
|
2018-02-01 17:04:50 +00:00
|
|
|
PaperTrail.request.whodunnit = orig_name
|
2014-06-17 14:58:53 +00:00
|
|
|
end
|
|
|
|
|
2017-04-01 06:28:55 +00:00
|
|
|
it "returns the originator for the model at a given state" do
|
|
|
|
expect(widget.paper_trail).to be_live
|
|
|
|
expect(widget.paper_trail.originator).to eq(orig_name)
|
2018-02-01 17:04:50 +00:00
|
|
|
::PaperTrail.request(whodunnit: new_name) {
|
2018-12-04 21:10:35 +00:00
|
|
|
widget.update(name: "Elizabeth")
|
2017-04-01 06:28:55 +00:00
|
|
|
}
|
|
|
|
expect(widget.paper_trail.originator).to eq(new_name)
|
2014-06-18 15:01:38 +00:00
|
|
|
end
|
|
|
|
|
2017-04-01 06:28:55 +00:00
|
|
|
it "returns the appropriate originator" do
|
2018-12-04 21:10:35 +00:00
|
|
|
widget.update(name: "Andy")
|
2018-02-01 17:04:50 +00:00
|
|
|
PaperTrail.request.whodunnit = new_name
|
2018-12-04 21:10:35 +00:00
|
|
|
widget.update(name: "Elizabeth")
|
2017-04-01 06:28:55 +00:00
|
|
|
reified_widget = widget.versions[1].reify
|
|
|
|
expect(reified_widget.paper_trail.originator).to eq(orig_name)
|
|
|
|
expect(reified_widget).not_to be_new_record
|
|
|
|
end
|
2014-03-11 21:55:44 +00:00
|
|
|
|
2017-04-01 06:28:55 +00:00
|
|
|
it "can create a new instance with options[:dup]" do
|
2018-12-04 21:10:35 +00:00
|
|
|
widget.update(name: "Andy")
|
2018-02-01 17:04:50 +00:00
|
|
|
PaperTrail.request.whodunnit = new_name
|
2018-12-04 21:10:35 +00:00
|
|
|
widget.update(name: "Elizabeth")
|
2017-04-01 06:28:55 +00:00
|
|
|
reified_widget = widget.versions[1].reify(dup: true)
|
|
|
|
expect(reified_widget.paper_trail.originator).to eq(orig_name)
|
|
|
|
expect(reified_widget).to be_new_record
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2014-03-11 21:55:44 +00:00
|
|
|
|
2017-04-01 06:28:55 +00:00
|
|
|
describe "#version_at", versioning: true do
|
|
|
|
context "Timestamp argument is AFTER object has been destroyed" do
|
|
|
|
it "returns nil" do
|
|
|
|
widget.update_attribute(:name, "foobar")
|
|
|
|
widget.destroy
|
|
|
|
expect(widget.paper_trail.version_at(Time.now)).to be_nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2014-03-11 21:55:44 +00:00
|
|
|
|
2018-03-16 22:21:45 +00:00
|
|
|
describe "touch", versioning: true do
|
|
|
|
it "creates a version" do
|
|
|
|
expect { widget.touch }.to change {
|
|
|
|
widget.versions.count
|
|
|
|
}.by(+1)
|
|
|
|
end
|
|
|
|
|
2018-03-24 02:12:41 +00:00
|
|
|
context "request is disabled" do
|
|
|
|
it "does not create a version" do
|
|
|
|
count = widget.versions.count
|
|
|
|
PaperTrail.request(enabled: false) do
|
|
|
|
widget.touch
|
|
|
|
end
|
|
|
|
expect(count).to eq(count)
|
2018-03-16 22:21:45 +00:00
|
|
|
end
|
2017-04-01 06:28:55 +00:00
|
|
|
end
|
|
|
|
end
|
2014-02-12 23:27:10 +00:00
|
|
|
|
2018-01-23 03:21:08 +00:00
|
|
|
describe ".paper_trail.update_columns", versioning: true do
|
|
|
|
it "creates a version record" do
|
|
|
|
widget = Widget.create
|
|
|
|
expect(widget.versions.count).to eq(1)
|
2018-05-15 02:31:12 +00:00
|
|
|
widget.paper_trail.update_columns(name: "Bugle")
|
|
|
|
expect(widget.versions.count).to eq(2)
|
|
|
|
expect(widget.versions.last.event).to(eq("update"))
|
|
|
|
expect(widget.versions.last.changeset[:name]).to eq([nil, "Bugle"])
|
2018-01-23 03:21:08 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-04-01 06:28:55 +00:00
|
|
|
describe "#update", versioning: true do
|
|
|
|
it "creates a version record" do
|
|
|
|
widget = Widget.create
|
|
|
|
assert_equal 1, widget.versions.length
|
2018-12-04 21:10:35 +00:00
|
|
|
widget.update(name: "Bugle")
|
2017-04-01 06:28:55 +00:00
|
|
|
assert_equal 2, widget.versions.length
|
|
|
|
end
|
|
|
|
end
|
2013-08-27 20:34:16 +00:00
|
|
|
end
|