paper_trail_manager 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +54 -0
  3. data/.gitignore +3 -2
  4. data/.rubocop.yml +33 -0
  5. data/.ruby-version +1 -0
  6. data/Appraisals +15 -12
  7. data/CHANGES.md +24 -0
  8. data/Gemfile +2 -1
  9. data/README.md +130 -66
  10. data/Rakefile +19 -5
  11. data/app/controllers/paper_trail_manager/changes_controller.rb +119 -101
  12. data/app/helpers/paper_trail_manager/changes_helper.rb +17 -13
  13. data/app/views/paper_trail_manager/changes/_version.html.erb +1 -1
  14. data/app/views/paper_trail_manager/changes/index.atom.builder +23 -19
  15. data/app/views/paper_trail_manager/changes/index.html.erb +41 -28
  16. data/app/views/paper_trail_manager/changes/show.html.erb +9 -6
  17. data/gemfiles/rails_6.1_paper_trail_12.0_kaminari.gemfile +10 -0
  18. data/gemfiles/rails_6.1_paper_trail_12.0_will_paginate.gemfile +10 -0
  19. data/gemfiles/rails_7.0_paper_trail_12.0_kaminari.gemfile +10 -0
  20. data/gemfiles/rails_7.0_paper_trail_12.0_will_paginate.gemfile +10 -0
  21. data/gemfiles/rails_7.0_paper_trail_15.0_kaminari.gemfile +10 -0
  22. data/gemfiles/rails_7.0_paper_trail_15.0_will_paginate.gemfile +10 -0
  23. data/gemfiles/rails_7.1_paper_trail_15.0_kaminari.gemfile +10 -0
  24. data/gemfiles/rails_7.1_paper_trail_15.0_will_paginate.gemfile +10 -0
  25. data/lib/paper_trail_manager.rb +11 -9
  26. data/paper_trail_manager.gemspec +25 -24
  27. data/spec/app_template.rb +39 -0
  28. data/spec/integration/authorization_spec.rb +84 -0
  29. data/spec/integration/date_filter_spec.rb +84 -0
  30. data/spec/integration/navigation_spec.rb +5 -3
  31. data/spec/integration/paper_trail_manager_spec.rb +94 -110
  32. data/spec/integration/response_formats_spec.rb +73 -0
  33. data/spec/rails_helper.rb +6 -4
  34. data/spec/spec_helper.rb +7 -5
  35. data/spec/support/factories.rb +4 -3
  36. data/spec/support/rspec_html_matchers.rb +7 -0
  37. data/spec/unit/authorization_spec.rb +42 -0
  38. data/spec/unit/changes_helper_spec.rb +81 -0
  39. metadata +103 -238
  40. data/.travis.yml +0 -23
  41. data/gemfiles/rails_3.2.0_paper_trail_3.0_kaminari.gemfile +0 -10
  42. data/gemfiles/rails_3.2.0_paper_trail_3.0_will_paginate.gemfile +0 -10
  43. data/gemfiles/rails_3.2.0_paper_trail_4.0_kaminari.gemfile +0 -10
  44. data/gemfiles/rails_3.2.0_paper_trail_4.0_will_paginate.gemfile +0 -10
  45. data/gemfiles/rails_4.0.0_paper_trail_3.0_kaminari.gemfile +0 -9
  46. data/gemfiles/rails_4.0.0_paper_trail_3.0_will_paginate.gemfile +0 -9
  47. data/gemfiles/rails_4.0.0_paper_trail_4.0_kaminari.gemfile +0 -9
  48. data/gemfiles/rails_4.0.0_paper_trail_4.0_will_paginate.gemfile +0 -9
  49. data/gemfiles/rails_4.1.0_paper_trail_3.0_kaminari.gemfile +0 -9
  50. data/gemfiles/rails_4.1.0_paper_trail_3.0_will_paginate.gemfile +0 -9
  51. data/gemfiles/rails_4.1.0_paper_trail_4.0_kaminari.gemfile +0 -9
  52. data/gemfiles/rails_4.1.0_paper_trail_4.0_will_paginate.gemfile +0 -9
  53. data/gemfiles/rails_4.2.2_paper_trail_3.0_kaminari.gemfile +0 -9
  54. data/gemfiles/rails_4.2.2_paper_trail_3.0_will_paginate.gemfile +0 -9
  55. data/gemfiles/rails_4.2.2_paper_trail_4.0_kaminari.gemfile +0 -9
  56. data/gemfiles/rails_4.2.2_paper_trail_4.0_will_paginate.gemfile +0 -9
  57. data/spec/controllers/entities_controller_spec.rb +0 -125
  58. data/spec/controllers/platforms_controller_spec.rb +0 -125
  59. data/spec/dummy/.gitignore +0 -15
  60. data/spec/dummy/Gemfile +0 -9
  61. data/spec/dummy/README.rdoc +0 -261
  62. data/spec/dummy/Rakefile +0 -7
  63. data/spec/dummy/app/assets/images/rails.png +0 -0
  64. data/spec/dummy/app/assets/javascripts/application.js +0 -15
  65. data/spec/dummy/app/assets/stylesheets/application.css +0 -13
  66. data/spec/dummy/app/controllers/application_controller.rb +0 -6
  67. data/spec/dummy/app/controllers/entities_controller.rb +0 -83
  68. data/spec/dummy/app/controllers/platforms_controller.rb +0 -83
  69. data/spec/dummy/app/helpers/application_helper.rb +0 -2
  70. data/spec/dummy/app/helpers/entities_helper.rb +0 -2
  71. data/spec/dummy/app/helpers/platforms_helper.rb +0 -2
  72. data/spec/dummy/app/mailers/.gitkeep +0 -0
  73. data/spec/dummy/app/models/.gitkeep +0 -0
  74. data/spec/dummy/app/models/entity.rb +0 -6
  75. data/spec/dummy/app/models/platform.rb +0 -6
  76. data/spec/dummy/app/views/application/index.html.erb +0 -6
  77. data/spec/dummy/app/views/entities/_form.html.erb +0 -17
  78. data/spec/dummy/app/views/entities/edit.html.erb +0 -6
  79. data/spec/dummy/app/views/entities/index.html.erb +0 -21
  80. data/spec/dummy/app/views/entities/new.html.erb +0 -5
  81. data/spec/dummy/app/views/entities/show.html.erb +0 -5
  82. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  83. data/spec/dummy/app/views/platforms/_form.html.erb +0 -17
  84. data/spec/dummy/app/views/platforms/edit.html.erb +0 -6
  85. data/spec/dummy/app/views/platforms/index.html.erb +0 -21
  86. data/spec/dummy/app/views/platforms/new.html.erb +0 -5
  87. data/spec/dummy/app/views/platforms/show.html.erb +0 -5
  88. data/spec/dummy/config/application.rb +0 -64
  89. data/spec/dummy/config/boot.rb +0 -6
  90. data/spec/dummy/config/database.yml +0 -22
  91. data/spec/dummy/config/environment.rb +0 -5
  92. data/spec/dummy/config/environments/development.rb +0 -37
  93. data/spec/dummy/config/environments/production.rb +0 -67
  94. data/spec/dummy/config/environments/test.rb +0 -36
  95. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  96. data/spec/dummy/config/initializers/inflections.rb +0 -15
  97. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  98. data/spec/dummy/config/initializers/secret_token.rb +0 -7
  99. data/spec/dummy/config/initializers/session_store.rb +0 -8
  100. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  101. data/spec/dummy/config/locales/en.yml +0 -5
  102. data/spec/dummy/config/routes.rb +0 -8
  103. data/spec/dummy/config.ru +0 -4
  104. data/spec/dummy/db/migrate/20110228091428_create_entities.rb +0 -14
  105. data/spec/dummy/db/migrate/20110228093241_create_platforms.rb +0 -14
  106. data/spec/dummy/db/migrate/20110228094444_create_versions.rb +0 -18
  107. data/spec/dummy/db/schema.rb +0 -41
  108. data/spec/dummy/db/seeds.rb +0 -7
  109. data/spec/dummy/doc/README_FOR_APP +0 -2
  110. data/spec/dummy/lib/assets/.gitkeep +0 -0
  111. data/spec/dummy/lib/tasks/.gitkeep +0 -0
  112. data/spec/dummy/log/.gitkeep +0 -0
  113. data/spec/dummy/public/404.html +0 -26
  114. data/spec/dummy/public/422.html +0 -26
  115. data/spec/dummy/public/500.html +0 -25
  116. data/spec/dummy/public/favicon.ico +0 -0
  117. data/spec/dummy/public/index.html +0 -241
  118. data/spec/dummy/public/robots.txt +0 -5
  119. data/spec/dummy/script/rails +0 -6
  120. data/spec/dummy/test/fixtures/.gitkeep +0 -0
  121. data/spec/dummy/test/functional/.gitkeep +0 -0
  122. data/spec/dummy/test/integration/.gitkeep +0 -0
  123. data/spec/dummy/test/performance/browsing_test.rb +0 -12
  124. data/spec/dummy/test/test_helper.rb +0 -13
  125. data/spec/dummy/test/unit/.gitkeep +0 -0
  126. data/spec/dummy/vendor/assets/javascripts/.gitkeep +0 -0
  127. data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
  128. data/spec/dummy/vendor/plugins/.gitkeep +0 -0
  129. data/spec/helpers/entities_helper_spec.rb +0 -15
  130. data/spec/helpers/platforms_helper_spec.rb +0 -15
  131. data/spec/models/entity_spec.rb +0 -14
  132. data/spec/models/platform_spec.rb +0 -14
  133. data/spec/requests/entities_spec.rb +0 -11
  134. data/spec/requests/platforms_spec.rb +0 -11
  135. data/spec/routing/entities_routing_spec.rb +0 -35
  136. data/spec/routing/platforms_routing_spec.rb +0 -35
  137. data/spec/views/entities/edit.html.erb_spec.rb +0 -15
  138. data/spec/views/entities/index.html.erb_spec.rb +0 -14
  139. data/spec/views/entities/new.html.erb_spec.rb +0 -15
  140. data/spec/views/entities/show.html.erb_spec.rb +0 -11
  141. data/spec/views/platforms/edit.html.erb_spec.rb +0 -15
  142. data/spec/views/platforms/index.html.erb_spec.rb +0 -14
  143. data/spec/views/platforms/new.html.erb_spec.rb +0 -15
  144. data/spec/views/platforms/show.html.erb_spec.rb +0 -11
@@ -1,31 +1,32 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
 
5
6
  Gem::Specification.new do |spec|
6
- spec.name = "paper_trail_manager"
7
- spec.version = "0.6.0"
8
- spec.authors = ["Igal Koshevoy", "Reid Beels"]
9
- spec.authors = ["mail@reidbeels.com"]
10
- spec.summary = "A user interface for `paper_trail` versioning data in Ruby on Rails 3 applications."
11
- spec.description = "Browse, subscribe, view and revert changes to records when using Ruby on Rails 3 and the `paper_trail` gem."
12
- spec.homepage = "https://github.com/fusion94/paper_trail_manager"
13
- spec.license = "MIT"
14
-
7
+ spec.name = 'paper_trail_manager'
8
+ spec.version = '0.8.0'
9
+ spec.authors = ['Igal Koshevoy', 'Reid Beels']
10
+ spec.email = ['mail@reidbeels.com']
11
+ spec.summary = 'A user interface for `paper_trail` versioning data in Rails applications.'
12
+ spec.description = 'Browse, subscribe, view and revert changes to records when using Rails and the `paper_trail` gem.'
13
+ spec.homepage = 'https://github.com/DamageLabs/paper_trail_manager'
14
+ spec.license = 'MIT'
15
15
  spec.files = `git ls-files -z`.split("\x0")
16
16
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
- spec.require_paths = ["lib"]
19
-
20
- spec.add_dependency "rails", [">= 3.0", "< 5.0"]
21
- spec.add_dependency "paper_trail", [">= 3.0", "< 5.0"]
22
-
23
- spec.add_development_dependency "rake", "~> 10.4"
24
- spec.add_development_dependency "sqlite3", "~> 1.3"
25
- spec.add_development_dependency "factory_girl_rails", "~> 4.0"
26
- spec.add_development_dependency "rspec-rails", "~> 3.0"
27
- spec.add_development_dependency "rspec-activemodel-mocks", "~> 1.0"
28
- spec.add_development_dependency "rspec-its", "~> 1.0"
29
- spec.add_development_dependency "appraisal", "~> 1.0"
18
+ spec.require_paths = ['lib']
19
+ spec.required_ruby_version = '>= 3.1'
20
+ spec.add_dependency 'paper_trail', ['>= 12.0']
21
+ spec.add_dependency 'rails', ['>= 6.1', '< 8.0']
22
+ spec.add_dependency 'nokogiri', ['>= 1.18.3']
23
+ spec.add_dependency 'rails-html-sanitizer', ['>= 1.6.1']
24
+ spec.add_development_dependency 'appraisal', '~> 2.0'
25
+ spec.add_development_dependency 'factory_bot_rails', '~> 6.0'
26
+ spec.add_development_dependency 'rake', '~> 13.0'
27
+ spec.add_development_dependency 'rspec-activemodel-mocks', '~> 1.0'
28
+ spec.add_development_dependency 'rspec-html-matchers', '~> 0.10'
29
+ spec.add_development_dependency 'rspec-its', '~> 1.0'
30
+ spec.add_development_dependency 'rspec-rails', '~> 6.0'
31
+ spec.add_development_dependency 'sqlite3', '~> 1.7'
30
32
  end
31
-
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ gem 'paper_trail_manager', path: __FILE__ + '/../../../'
4
+
5
+ # Remove auto-generated request specs from dummy app
6
+ remove_file 'spec/requests/entities_spec.rb' if File.exist?('spec/requests/entities_spec.rb')
7
+ remove_file 'spec/requests/platforms_spec.rb' if File.exist?('spec/requests/platforms_spec.rb')
8
+
9
+ generate 'paper_trail:install'
10
+ generate 'resource', 'entity name:string status:string --no-controller-specs --no-helper-specs'
11
+ generate 'resource', 'platform name:string status:string --no-controller-specs --no-helper-specs'
12
+
13
+ # Remove auto-generated spec files that conflict with our factories
14
+ remove_file 'spec/models/entity_spec.rb' if File.exist?('spec/models/entity_spec.rb')
15
+ remove_file 'spec/models/platform_spec.rb' if File.exist?('spec/models/platform_spec.rb')
16
+
17
+ model_body = <<-MODEL
18
+ has_paper_trail
19
+
20
+ validates :name, presence: true
21
+ validates :status, presence: true
22
+ MODEL
23
+
24
+ inject_into_class 'app/models/entity.rb', 'Entity', model_body
25
+ inject_into_class 'app/models/platform.rb', 'Platform', model_body
26
+
27
+ route "resources :changes, controller: 'paper_trail_manager/changes'"
28
+ route "root to: 'paper_trail_manager/changes#index'"
29
+
30
+ # Allow YAML deserialization of ActiveSupport::TimeWithZone (Ruby 3.1+ Psych 4)
31
+ initializer 'permitted_classes.rb', <<~RUBY
32
+ Rails.application.config.active_record.yaml_column_permitted_classes = [
33
+ ActiveSupport::TimeWithZone,
34
+ ActiveSupport::TimeZone,
35
+ Time
36
+ ]
37
+ RUBY
38
+
39
+ rake 'db:migrate db:test:prepare'
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe PaperTrailManager, 'authorization integration', versioning: true do
6
+ let(:entity) { FactoryBot.create(:entity, name: 'Test Entity', status: 'Active') }
7
+
8
+ before do
9
+ entity
10
+ entity.update(status: 'Updated')
11
+ end
12
+
13
+ after do
14
+ default = proc { true }
15
+ PaperTrailManager.allow_index_block = default
16
+ PaperTrailManager.allow_show_block = default
17
+ PaperTrailManager.allow_revert_block = default
18
+ end
19
+
20
+ describe 'index' do
21
+ context 'when not authorized' do
22
+ before do
23
+ PaperTrailManager.allow_index_when { |_controller| false }
24
+ end
25
+
26
+ it 'redirects with an error flash' do
27
+ get changes_path
28
+ expect(response).to have_http_status(:redirect)
29
+ expect(flash[:error]).to eq('You do not have permission to list changes.')
30
+ end
31
+ end
32
+ end
33
+
34
+ describe 'show' do
35
+ context 'when not authorized' do
36
+ before do
37
+ PaperTrailManager.allow_show_when { |_controller, _version| false }
38
+ end
39
+
40
+ it 'redirects with an error flash' do
41
+ get change_path(entity.versions.last)
42
+ expect(response).to have_http_status(:redirect)
43
+ expect(flash[:error]).to eq('You do not have permission to show that change.')
44
+ end
45
+ end
46
+
47
+ context 'when change does not exist' do
48
+ it 'redirects with an error flash' do
49
+ get change_path(id: 999999)
50
+ expect(response).to have_http_status(:redirect)
51
+ expect(flash[:error]).to eq('No such version.')
52
+ end
53
+ end
54
+ end
55
+
56
+ describe 'revert' do
57
+ context 'when not authorized' do
58
+ before do
59
+ PaperTrailManager.allow_revert_when { |_controller, _version| false }
60
+ end
61
+
62
+ it 'redirects with an error flash' do
63
+ put change_path(entity.versions.last)
64
+ expect(response).to have_http_status(:redirect)
65
+ expect(flash[:error]).to eq('You do not have permission to revert this change.')
66
+ end
67
+ end
68
+
69
+ context 'when change does not exist' do
70
+ it 'redirects with an error flash' do
71
+ put change_path(id: 999999)
72
+ expect(response).to have_http_status(:redirect)
73
+ expect(flash[:error]).to eq('No such version.')
74
+ end
75
+ end
76
+ end
77
+
78
+ describe 'filtering by non-existent type' do
79
+ it 'returns an empty changes list' do
80
+ get changes_path(type: 'NonExistentModel')
81
+ expect(response.body).to include('No changes found')
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe PaperTrailManager, 'date range filtering', versioning: true do
6
+ let(:entity) { FactoryBot.create(:entity, name: 'Test Entity', status: 'Active') }
7
+
8
+ before do
9
+ entity
10
+ entity.update(status: 'Updated')
11
+ end
12
+
13
+ describe 'index with date filters' do
14
+ context 'with from parameter' do
15
+ it 'shows changes on or after the date' do
16
+ get changes_path(from: Date.today.to_s)
17
+ expect(response).to have_http_status(:ok)
18
+ expect(response.body).to have_tag('.change_row')
19
+ end
20
+
21
+ it 'returns no changes for future date' do
22
+ get changes_path(from: (Date.today + 1).to_s)
23
+ expect(response.body).to include('No changes found')
24
+ end
25
+ end
26
+
27
+ context 'with to parameter' do
28
+ it 'shows changes on or before the date' do
29
+ get changes_path(to: Date.today.to_s)
30
+ expect(response).to have_http_status(:ok)
31
+ expect(response.body).to have_tag('.change_row')
32
+ end
33
+
34
+ it 'returns no changes for past date' do
35
+ get changes_path(to: (Date.today - 1).to_s)
36
+ expect(response.body).to include('No changes found')
37
+ end
38
+ end
39
+
40
+ context 'with from and to combined' do
41
+ it 'shows changes within the range' do
42
+ get changes_path(from: Date.today.to_s, to: Date.today.to_s)
43
+ expect(response).to have_http_status(:ok)
44
+ expect(response.body).to have_tag('.change_row')
45
+ end
46
+ end
47
+
48
+ context 'combined with type filter' do
49
+ it 'respects both date and type filters' do
50
+ get changes_path(from: Date.today.to_s, type: 'Entity')
51
+ expect(response).to have_http_status(:ok)
52
+ expect(response.body).to have_tag('.change_item', text: /Entity/)
53
+ end
54
+ end
55
+
56
+ context 'with invalid date' do
57
+ it 'ignores invalid from date gracefully' do
58
+ get changes_path(from: 'not-a-date')
59
+ expect(response).to have_http_status(:ok)
60
+ expect(response.body).to have_tag('.change_row')
61
+ end
62
+
63
+ it 'ignores invalid to date gracefully' do
64
+ get changes_path(to: 'garbage')
65
+ expect(response).to have_http_status(:ok)
66
+ expect(response.body).to have_tag('.change_row')
67
+ end
68
+ end
69
+
70
+ context 'date filter form' do
71
+ it 'renders date inputs' do
72
+ get changes_path
73
+ expect(response.body).to have_tag('input[type="date"][name="from"]')
74
+ expect(response.body).to have_tag('input[type="date"][name="to"]')
75
+ end
76
+
77
+ it 'preserves date values in form' do
78
+ get changes_path(from: '2026-01-01', to: '2026-12-31')
79
+ expect(response.body).to have_tag('input[name="from"][value="2026-01-01"]')
80
+ expect(response.body).to have_tag('input[name="to"][value="2026-12-31"]')
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe "Navigation" do
4
- it "should be a valid app" do
5
- ::Rails.application.should be_a_kind_of(Rails::Application)
5
+ describe 'Navigation' do
6
+ it 'is a valid app' do
7
+ expect(::Rails.application).to be_a_kind_of(Rails::Application)
6
8
  end
7
9
  end
@@ -1,72 +1,55 @@
1
- require 'spec_helper'
2
-
3
- describe PaperTrailManager, :versioning => true do
4
- def version
5
- return assigns[:version]
6
- end
7
-
8
- def versions
9
- return assigns[:versions]
10
- end
11
-
12
- def item_types
13
- return versions.map(&:item_type).uniq.sort
14
- end
15
-
16
- def populate
17
- @reimu = FactoryGirl.create(:entity, :name => "Miko Hakurei Reimu", :status => "Highly Responsive to Prayers")
18
- @reimu.update_attributes(:name => "Hakurei Reimu", :status => "Phantasmagoria of Dimensional Dream")
19
- @reimu.update_attributes(:status => "Perfect Cherry Blossom")
1
+ # frozen_string_literal: true
20
2
 
21
- @sakuya = FactoryGirl.create(:entity, :name => "Sakuya Izayoi", :status => "Flowering Night")
22
-
23
- @flanchan = FactoryGirl.create(:entity, :name => "Flandre Scarlet", :status => "The Embodiment of Scarlet Devil")
24
- @flanchan.destroy
25
-
26
- @kyuu_hachi = FactoryGirl.create(:platform, :name => "PC-9801", :status => "SUGOI!!1!")
27
- @kyuu_hachi.update_attributes(:status => "Kimochi warui.")
28
- @kyuu_hachi.destroy
29
-
30
- @uinodouzu = FactoryGirl.create(:platform, :name => "Mikorusofto Uinodouzu", :status => 'o-O')
31
- end
3
+ require 'spec_helper'
32
4
 
33
- context "without changes" do
34
- context "index" do
35
- it "should have no changes by default" do
36
- get "/changes"
5
+ describe PaperTrailManager, versioning: true do
6
+ context 'without changes' do
7
+ context 'when fetching the index' do
8
+ it 'has no changes by default' do
9
+ get '/changes'
37
10
 
38
- assigns[:versions].should be_empty
11
+ expect(response.body).to include('No changes found')
39
12
  end
40
13
  end
41
14
  end
42
15
 
43
- context "with changes" do
44
- before do
45
- populate
46
- end
16
+ context 'with changes' do
17
+ let(:reimu) { FactoryBot.create(:entity, name: 'Miko Hakurei Reimu', status: 'Highly Responsive to Prayers') }
18
+ let(:flanchan) { FactoryBot.create(:entity, name: 'Flandre Scarlet', status: 'The Embodiment of Scarlet Devil') }
19
+ let(:sakuya) { FactoryBot.create(:entity, name: 'Sakuya Izayoi', status: 'Flowering Night') }
20
+ let(:kyuu_hachi) { FactoryBot.create(:platform, name: 'PC-9801', status: 'SUGOI!!1!') }
21
+ let!(:uinodouzu) { FactoryBot.create(:platform, name: 'Mikorusofto Uinodouzu', status: 'o-O') }
22
+
23
+ let!(:flanchan_id) { flanchan.id }
47
24
 
48
- after do
49
- Entity.destroy_all
50
- Platform.destroy_all
51
- PaperTrail::Version.destroy_all
25
+ before do
26
+ sakuya
27
+ reimu.update(name: 'Hakurei Reimu', status: 'Phantasmagoria of Dimensional Dream')
28
+ reimu.update(status: 'Perfect Cherry Blossom')
29
+ flanchan.destroy
30
+ kyuu_hachi.update(status: 'Kimochi warui.')
31
+ kyuu_hachi.destroy
32
+ uinodouzu
52
33
  end
53
34
 
54
- context "index" do
55
- context "when getting all changes" do
56
- context "and authorized" do
57
- context "and getting default index" do
35
+ describe 'index' do
36
+ context 'when getting all changes' do
37
+ context 'with authorization' do
38
+ context 'when getting default index' do
58
39
  before { get changes_path }
59
40
 
60
- it "should have all changes" do
61
- versions.size.should == 10
41
+ it 'has all changes' do
42
+ expect(response.body).to have_tag('.change_row', count: 10)
62
43
  end
63
44
 
64
- it "should have changes for all changed item types" do
65
- item_types.should == ["Entity", "Platform"]
45
+ it 'has changes for all changed item types' do
46
+ expect(response.body).to have_tag('.change_item', text: /Entity/)
47
+ expect(response.body).to have_tag('.change_item', text: /Platform/)
66
48
  end
67
49
 
68
- it "should order changes with newest and highest id at the top" do
69
- versions.map(&:id).should == versions.sort_by { |o| [o.created_at, o.id] }.reverse.map(&:id)
50
+ it 'orders changes with newest and highest id at the top' do
51
+ ids = response.body.scan(/Change #(\d+)/).flatten.map(&:to_i)
52
+ expect(ids).to eq ids.sort.reverse
70
53
  end
71
54
  end
72
55
  end
@@ -77,16 +60,17 @@ describe PaperTrailManager, :versioning => true do
77
60
  # end
78
61
  end
79
62
 
80
- context "when getting changes for a specific type" do
81
- context "that exists" do
82
- before { get changes_path(:type => "Entity") }
63
+ context 'when getting changes for a specific type' do
64
+ context 'when changes exist' do
65
+ before { get changes_path(type: 'Entity') }
83
66
 
84
- it "should show a subset of the changes" do
85
- versions.size.should == 6
67
+ it 'shows a subset of the changes' do
68
+ expect(response.body).to have_tag('.change_row', count: 6)
86
69
  end
87
70
 
88
- it "should have changes only for that type" do
89
- item_types.should == ["Entity"]
71
+ it 'has changes only for that type' do
72
+ expect(response.body).to have_tag('.change_item', text: /Entity/)
73
+ expect(response.body).not_to have_tag('.change_item', text: /Platform/)
90
74
  end
91
75
  end
92
76
 
@@ -96,20 +80,21 @@ describe PaperTrailManager, :versioning => true do
96
80
  # end
97
81
  end
98
82
 
99
- context "when getting changes for a specific record" do
100
- context "that exists" do
101
- before { get changes_path(:type => "Entity", :id => @reimu.id) }
83
+ context 'when getting changes for a specific record' do
84
+ context 'when changes exist' do
85
+ before { get changes_path(type: 'Entity', id: reimu.id) }
102
86
 
103
- it "should show a subset of the changes" do
104
- versions.size.should == 3
87
+ it 'shows a subset of the changes' do
88
+ expect(response.body).to have_tag('.change_row', count: 3)
105
89
  end
106
90
 
107
- it "should have changes only for that type" do
108
- item_types.should == ["Entity"]
91
+ it 'has changes only for that type' do
92
+ expect(response.body).to have_tag('.change_item', text: /Entity/)
93
+ expect(response.body).not_to have_tag('.change_item', text: /Platform/)
109
94
  end
110
95
 
111
- it "should have changes only for that record" do
112
- versions.map(&:item_id).uniq.should == [@reimu.id]
96
+ it 'has changes only for that record' do
97
+ expect(response.body.scan(%r{/entities/(#{reimu.id})}).flatten.uniq).to eq [reimu.id.to_s]
113
98
  end
114
99
  end
115
100
 
@@ -120,24 +105,25 @@ describe PaperTrailManager, :versioning => true do
120
105
  end
121
106
  end
122
107
 
123
- context "show a change" do
124
- context "that exists" do
125
- context "when authorized" do
108
+ describe 'showing a change' do
109
+ context 'when the change exists' do
110
+ context 'when authorized' do
111
+ let(:version) { reimu.versions.last }
112
+
126
113
  before do
127
- @version = @reimu.versions.last
128
- get change_path(@version)
114
+ get change_path(version)
129
115
  end
130
116
 
131
- it "should show the requested change" do
132
- version.should == @version
117
+ it 'shows the requested change' do
118
+ expect(response.body).to have_tag('.change_id', text: "Change ##{version.id}")
133
119
  end
134
120
 
135
- it "should show a change with the right event" do
136
- version.event.should == "update"
121
+ it 'shows a change with the right event' do
122
+ expect(response.body).to have_tag('.change_event_update')
137
123
  end
138
124
 
139
- it "should be associated with the expected record" do
140
- version.item.should == @reimu
125
+ it 'is associated with the expected record' do
126
+ expect(response.body).to have_tag('.change_item', text: "Entity #{reimu.id}")
141
127
  end
142
128
  end
143
129
 
@@ -152,50 +138,48 @@ describe PaperTrailManager, :versioning => true do
152
138
  # it "should display an error that the change doesn't exist"
153
139
  # end
154
140
  end
155
- end
156
-
157
- context "when rolling back changes" do
158
- context "that that exist" do
159
- before(:each) { populate }
160
141
 
161
- context "when authorized" do
162
- it "should rollback a newly-created record by deleting it" do
163
- Entity.exists?(@reimu.id).should be_truthy
142
+ describe 'rolling back changes' do
143
+ context 'when changes exist' do
144
+ context 'when authorized' do
145
+ it 'rollbacks a newly-created record by deleting it' do
146
+ expect(Entity).to exist(reimu.id)
164
147
 
165
- put change_path(@reimu.versions.first)
148
+ put change_path(reimu.versions.first)
166
149
 
167
- Entity.exists?(@reimu.id).should be_falsey
168
- end
150
+ expect(Entity).not_to exist(reimu.id)
151
+ end
169
152
 
170
- it "should rollback an edit by reverting to the previous state" do
171
- @reimu.reload
172
- @reimu.status.should == "Perfect Cherry Blossom"
153
+ it 'rollbacks an edit by reverting to the previous state' do
154
+ reimu.reload
155
+ expect(reimu.status).to eq 'Perfect Cherry Blossom'
173
156
 
174
- put change_path(@reimu.versions.last)
157
+ put change_path(reimu.versions.last)
175
158
 
176
- @reimu.reload
177
- @reimu.status.should == "Phantasmagoria of Dimensional Dream"
178
- end
159
+ reimu.reload
160
+ expect(reimu.status).to eq 'Phantasmagoria of Dimensional Dream'
161
+ end
179
162
 
180
- it "should rollback a delete by restoring the record" do
181
- Entity.exists?(@flanchan.id).should be_falsey
163
+ it 'rollbacks a delete by restoring the record' do
164
+ expect(Entity.exists?(flanchan_id)).to be_falsey
182
165
 
183
- put change_path(PaperTrail::Version.where(:item_id => @flanchan.id, :item_type => "Entity").last)
166
+ put change_path(PaperTrail::Version.where(item_id: flanchan_id, item_type: 'Entity').last)
184
167
 
185
- flanchan = Entity.find(@flanchan.id)
186
- flanchan.status.should == "The Embodiment of Scarlet Devil"
168
+ found = Entity.find(flanchan_id)
169
+ expect(found.status).to eq 'The Embodiment of Scarlet Devil'
170
+ end
187
171
  end
172
+
173
+ # TODO
174
+ # context "when not authorized" do
175
+ # it "should display an error if user is not allowed to revert that change"
176
+ # end
188
177
  end
189
178
 
190
179
  # TODO
191
- # context "when not authorized" do
192
- # it "should display an error if user is not allowed to revert that change"
180
+ # context "that don't exist" do
181
+ # it "should display an error that the change doesn't exist"
193
182
  # end
194
183
  end
195
-
196
- # TODO
197
- # context "that don't exist" do
198
- # it "should display an error that the change doesn't exist"
199
- # end
200
184
  end
201
185
  end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe PaperTrailManager, 'response formats', versioning: true do
6
+ let(:entity) { FactoryBot.create(:entity, name: 'Format Test', status: 'Active') }
7
+
8
+ before do
9
+ entity
10
+ entity.update(status: 'Updated')
11
+ end
12
+
13
+ describe 'JSON format' do
14
+ context 'index' do
15
+ it 'returns valid JSON with version data' do
16
+ get changes_path(format: :json)
17
+ expect(response.content_type).to include('application/json')
18
+ json = JSON.parse(response.body)
19
+ expect(json).to be_an(Array)
20
+ expect(json.length).to be >= 2
21
+ end
22
+
23
+ it 'respects type filter' do
24
+ get changes_path(format: :json, type: 'Entity')
25
+ json = JSON.parse(response.body)
26
+ json.each do |version|
27
+ expect(version['item_type']).to eq('Entity')
28
+ end
29
+ end
30
+
31
+ it 'respects id filter' do
32
+ get changes_path(format: :json, type: 'Entity', id: entity.id)
33
+ json = JSON.parse(response.body)
34
+ json.each do |version|
35
+ expect(version['item_id']).to eq(entity.id)
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'show' do
41
+ it 'returns valid JSON for a single version' do
42
+ version = entity.versions.last
43
+ get change_path(version, format: :json)
44
+ expect(response.content_type).to include('application/json')
45
+ json = JSON.parse(response.body)
46
+ expect(json['id']).to eq(version.id)
47
+ expect(json['item_type']).to eq('Entity')
48
+ end
49
+ end
50
+ end
51
+
52
+ describe 'Atom format' do
53
+ context 'index' do
54
+ it 'returns valid XML' do
55
+ get changes_path(format: :atom)
56
+ expect(response.content_type).to include('application/atom+xml')
57
+ expect(response.body).to include('<feed')
58
+ expect(response.body).to include('<entry>')
59
+ end
60
+
61
+ it 'includes version entries' do
62
+ get changes_path(format: :atom)
63
+ expect(response.body).to include('Entity')
64
+ end
65
+
66
+ it 'respects type filter' do
67
+ get changes_path(format: :atom, type: 'Entity')
68
+ expect(response.body).to include('Entity')
69
+ expect(response.body).not_to include('Platform')
70
+ end
71
+ end
72
+ end
73
+ end
data/spec/rails_helper.rb CHANGED
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is copied to spec/ when you run 'rails generate rspec:install'
2
- ENV["RAILS_ENV"] ||= 'test'
3
- require File.expand_path("../dummy/config/environment", __FILE__)
4
- require "rspec/rails"
5
- require "rspec/active_model/mocks"
4
+ ENV['RAILS_ENV'] ||= 'test'
5
+ require File.expand_path('dummy/config/environment', __dir__)
6
+ require 'rspec/rails'
7
+ require 'rspec/active_model/mocks'
6
8
 
7
9
  RSpec.configure do |config|
8
10
  # If you're not using ActiveRecord, or you'd prefer not to run each of your