tessa 2.0 → 6.0.0.rc2

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -18
  3. data/app/assets/javascripts/tessa.esm.js +212 -173
  4. data/app/assets/javascripts/tessa.js +206 -167
  5. data/app/javascript/activestorage/file_checksum.ts +76 -0
  6. data/app/javascript/tessa/index.ts +264 -0
  7. data/app/javascript/tessa/types.ts +34 -0
  8. data/config/routes.rb +0 -1
  9. data/lib/tessa/simple_form/asset_input.rb +24 -25
  10. data/lib/tessa/version.rb +1 -1
  11. data/lib/tessa.rb +0 -80
  12. data/package.json +7 -2
  13. data/rollup.config.js +5 -5
  14. data/spec/dummy/app/models/single_asset_model.rb +1 -1
  15. data/spec/dummy/app/models/single_asset_model_form.rb +3 -5
  16. data/spec/dummy/bin/rails +2 -2
  17. data/spec/dummy/bin/rake +2 -2
  18. data/spec/dummy/bin/setup +14 -6
  19. data/spec/dummy/bin/yarn +9 -3
  20. data/spec/dummy/config/application.rb +11 -9
  21. data/spec/dummy/config/boot.rb +1 -1
  22. data/spec/dummy/config/environment.rb +1 -1
  23. data/spec/dummy/config/environments/development.rb +34 -5
  24. data/spec/dummy/config/environments/production.rb +49 -10
  25. data/spec/dummy/config/environments/test.rb +28 -12
  26. data/spec/dummy/config/initializers/backtrace_silencers.rb +4 -3
  27. data/spec/dummy/config/initializers/content_security_policy.rb +5 -0
  28. data/spec/dummy/config/initializers/filter_parameter_logging.rb +3 -1
  29. data/spec/dummy/config/initializers/new_framework_defaults_6_1.rb +67 -0
  30. data/spec/dummy/config/initializers/permissions_policy.rb +11 -0
  31. data/spec/dummy/config/initializers/wrap_parameters.rb +5 -0
  32. data/spec/dummy/config/locales/en.yml +1 -1
  33. data/spec/dummy/config/routes.rb +1 -1
  34. data/spec/dummy/config/storage.yml +31 -0
  35. data/spec/dummy/config.ru +2 -1
  36. data/spec/dummy/db/migrate/20230406194400_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
  37. data/spec/dummy/db/migrate/20230406194401_create_active_storage_variant_records.active_storage.rb +27 -0
  38. data/spec/dummy/db/schema.rb +15 -7
  39. data/tessa.gemspec +4 -5
  40. data/tsconfig.json +10 -0
  41. data/yarn.lock +74 -7
  42. metadata +36 -74
  43. data/app/javascript/activestorage/file_checksum.js +0 -53
  44. data/app/javascript/tessa/index.js.coffee +0 -183
  45. data/lib/tasks/tessa.rake +0 -18
  46. data/lib/tessa/active_storage/asset_wrapper.rb +0 -32
  47. data/lib/tessa/asset/failure.rb +0 -37
  48. data/lib/tessa/asset.rb +0 -47
  49. data/lib/tessa/asset_change.rb +0 -49
  50. data/lib/tessa/asset_change_set.rb +0 -49
  51. data/lib/tessa/config.rb +0 -16
  52. data/lib/tessa/controller_helpers.rb +0 -16
  53. data/lib/tessa/fake_connection.rb +0 -29
  54. data/lib/tessa/jobs/migrate_assets_job.rb +0 -222
  55. data/lib/tessa/model/dynamic_extensions.rb +0 -145
  56. data/lib/tessa/model/field.rb +0 -77
  57. data/lib/tessa/model.rb +0 -94
  58. data/lib/tessa/rack_upload_proxy.rb +0 -41
  59. data/lib/tessa/response_factory.rb +0 -15
  60. data/lib/tessa/upload/uploads_file.rb +0 -18
  61. data/lib/tessa/upload.rb +0 -31
  62. data/lib/tessa/view_helpers.rb +0 -23
  63. data/spec/dummy/app/models/multiple_asset_model.rb +0 -8
  64. data/spec/support/remote_call_macro.rb +0 -40
  65. data/spec/tessa/asset/failure_spec.rb +0 -48
  66. data/spec/tessa/asset_change_set_spec.rb +0 -198
  67. data/spec/tessa/asset_change_spec.rb +0 -86
  68. data/spec/tessa/asset_spec.rb +0 -196
  69. data/spec/tessa/config_spec.rb +0 -70
  70. data/spec/tessa/controller_helpers_spec.rb +0 -55
  71. data/spec/tessa/jobs/migrate_assets_job_spec.rb +0 -247
  72. data/spec/tessa/model_field_spec.rb +0 -72
  73. data/spec/tessa/model_spec.rb +0 -325
  74. data/spec/tessa/rack_upload_proxy_spec.rb +0 -83
  75. data/spec/tessa/upload/uploads_file_spec.rb +0 -72
  76. data/spec/tessa/upload_spec.rb +0 -125
  77. data/spec/tessa_spec.rb +0 -23
@@ -1,196 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Tessa::Asset do
4
- subject(:asset) { described_class.new(args) }
5
- let(:args) {
6
- {
7
- id: 123,
8
- status: 'completed',
9
- strategy: 'default',
10
- meta: { name: "foo" },
11
- public_url: "http://example.com/public",
12
- private_url: "http://example.com/private",
13
- private_download_url: "http://example.com/private?download",
14
- delete_url: "http://example.com/delete",
15
- }
16
- }
17
-
18
- describe "#initialize" do
19
- context "with all arguments" do
20
- it "sets id to attribute" do
21
- expect(asset.id).to eq(args[:id])
22
- end
23
-
24
- it "sets status to attribute" do
25
- expect(asset.status).to eq(args[:status])
26
- end
27
-
28
- it "sets strategy to attribute" do
29
- expect(asset.strategy).to eq(args[:strategy])
30
- end
31
-
32
- it "sets meta to attribute" do
33
- expect(asset.meta).to eq(args[:meta])
34
- end
35
-
36
- it "sets public_url to attribute" do
37
- expect(asset.public_url).to eq(args[:public_url])
38
- end
39
-
40
- it "sets private_url to attribute" do
41
- expect(asset.private_url).to eq(args[:private_url])
42
- end
43
-
44
- it "sets private_download_url to attribute" do
45
- expect(asset.private_download_url).to eq(args[:private_download_url])
46
- end
47
-
48
- it "sets delete_url to attribute" do
49
- expect(asset.delete_url).to eq(args[:delete_url])
50
- end
51
-
52
- end
53
- end
54
-
55
- describe "#complete!" do
56
- subject(:call) { asset.complete!(call_args) }
57
-
58
- include_examples "remote call macro", :patch, "/assets/123/completed", Tessa::Asset
59
- end
60
-
61
- describe "#cancel!" do
62
- subject(:call) { asset.cancel!(call_args) }
63
-
64
- include_examples "remote call macro", :patch, "/assets/123/cancelled", Tessa::Asset
65
- end
66
-
67
- describe "#delete!" do
68
- subject(:call) { asset.delete!(call_args) }
69
-
70
- include_examples "remote call macro", :delete, "/assets/123", Tessa::Asset
71
- end
72
-
73
- describe "#failure?" do
74
- it "returns false" do
75
- expect(asset.failure?).to be(false)
76
- end
77
- end
78
-
79
- describe ".find" do
80
- let(:faraday_stubs) {
81
- Faraday::Adapter::Test::Stubs.new do |stub|
82
- stub.get("/assets/#{id_query}") { |env| [200, {}, remote_response.to_json] }
83
- end
84
- }
85
- let(:connection) { Faraday.new { |f| f.adapter :test, faraday_stubs } }
86
-
87
- context "with a single id" do
88
- let(:id_query) { "ID" }
89
- let(:remote_response) { {} }
90
-
91
- it "calls get('/assets/ID') on connection" do
92
- expect(connection).to receive(:get).with("/assets/ID").and_call_original
93
- described_class.find("ID", connection: connection)
94
- end
95
-
96
- it "returns an instance of Asset" do
97
- response = described_class.find("ID", connection: connection)
98
- expect(response).to be_a(described_class)
99
- end
100
-
101
- it "defaults connection to Tessa.config.connection" do
102
- expect(Tessa.config).to receive(:connection).and_return(connection)
103
- expect(connection).to receive(:get).and_call_original
104
- described_class.find("ID")
105
- end
106
-
107
- context "with attributes in response" do
108
- subject(:response) { described_class.find("ID", connection: connection) }
109
- let(:remote_response) { args }
110
-
111
- it "sets attributes on models" do
112
- expect(response.id).to eq(args[:id])
113
- expect(response.status).to eq(args[:status])
114
- expect(response.meta).to eq(args[:meta])
115
- end
116
- end
117
- end
118
-
119
- context "with multiple ids" do
120
- subject(:response) {
121
- described_class.find("ID1", "ID2", connection: connection)
122
- }
123
- let(:remote_response) { [{}] }
124
- let(:id_query) { "ID1,ID2" }
125
-
126
- it "calls get('/assets/ID1,ID2') on connection" do
127
- expect(connection).to receive(:get).with("/assets/ID1,ID2").and_call_original
128
- response
129
- end
130
-
131
- it "returns instances of Asset" do
132
- expect(response).to all(be_a(described_class))
133
- end
134
-
135
- context "with attributes in response" do
136
- let(:remote_response) { [args, args] }
137
-
138
- it "sets attributes on models" do
139
- expect(response[0].id).to eq(args[:id])
140
- expect(response[1].id).to eq(args[:id])
141
- end
142
- end
143
- end
144
- end
145
-
146
- describe ".create" do
147
- let(:upload) { instance_double(Tessa::Upload) }
148
-
149
- before :each do
150
- allow(Tessa::Upload).to receive(:create).and_return(upload)
151
- allow(upload).to receive(:upload_file)
152
- end
153
-
154
- it "requires a file param" do
155
- expect { described_class.create }.to raise_error(ArgumentError)
156
- expect { described_class.create(file: __FILE__) }.to_not raise_error
157
- end
158
-
159
- it "creates a new upload" do
160
- expect(Tessa::Upload)
161
- .to receive(:create).with(hash_including(foo: :bar, baz: :boom)).and_return(upload)
162
- described_class.create(file: __FILE__, foo: :bar, baz: :boom)
163
- end
164
-
165
- it "uploads the passed file to the upload's URL" do
166
- expect(Tessa::Upload).to receive(:create).and_return(upload)
167
- expect(upload).to receive(:upload_file).with(__FILE__)
168
- described_class.create(file: __FILE__)
169
- end
170
-
171
- it "infers the file size, name, and date" do
172
- file = Tempfile.new("test")
173
- file.write "abc"
174
- file.close
175
- expected_values = {
176
- size: 3,
177
- name: File.basename(file.path),
178
- date: File.mtime(file.path),
179
- }
180
- expect(Tessa::Upload)
181
- .to receive(:create).with(hash_including(expected_values)).and_return(upload)
182
- described_class.create(file: file.path)
183
- end
184
-
185
- it "allows overriding inferred values" do
186
- expected_values = {
187
- size: 1,
188
- name: "my-file",
189
- date: "123",
190
- }
191
- expect(Tessa::Upload)
192
- .to receive(:create).with(hash_including(expected_values)).and_return(upload)
193
- described_class.create(file: __FILE__, **expected_values)
194
- end
195
- end
196
- end
@@ -1,70 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Tessa::Config do
4
- let(:cfg) { Tessa::Config.new }
5
-
6
- shared_examples_for "defaults to environment variable" do
7
- around { |ex| swap_environment_var(variable_name, 'from-env') { ex.run } }
8
-
9
- it { is_expected.to eq("from-env") }
10
-
11
- def swap_environment_var(var, new_val)
12
- old_val = ENV[var]
13
- ENV[var] = new_val
14
- yield
15
- ENV[var] = old_val
16
- end
17
- end
18
-
19
- describe "#username" do
20
- it_behaves_like "defaults to environment variable" do
21
- let(:variable_name) { 'TESSA_USERNAME' }
22
- subject { cfg.username }
23
- end
24
-
25
- it "behaves like a normal accessor" do
26
- cfg.username = "my-new-value"
27
- expect(cfg.username).to eq("my-new-value")
28
- end
29
- end
30
-
31
- describe "#password" do
32
- it_behaves_like "defaults to environment variable" do
33
- let(:variable_name) { 'TESSA_PASSWORD' }
34
- subject { cfg.password }
35
- end
36
-
37
- it "behaves like a normal accessor" do
38
- cfg.password = "my-new-value"
39
- expect(cfg.password).to eq("my-new-value")
40
- end
41
- end
42
-
43
- describe "#url" do
44
- it_behaves_like "defaults to environment variable" do
45
- let(:variable_name) { 'TESSA_URL' }
46
- subject { cfg.url }
47
- end
48
-
49
- it "behaves like a normal accessor" do
50
- cfg.url = "my-new-value"
51
- expect(cfg.url).to eq("my-new-value")
52
- end
53
- end
54
-
55
- describe "#strategy" do
56
- it_behaves_like "defaults to environment variable" do
57
- let(:variable_name) { 'TESSA_STRATEGY' }
58
- subject { cfg.strategy }
59
- end
60
-
61
- it "uses the string 'default' when no envvar passed" do
62
- expect(cfg.strategy).to eq("default")
63
- end
64
-
65
- it "behaves like a normal accessor" do
66
- cfg.strategy = "my-new-value"
67
- expect(cfg.strategy).to eq("my-new-value")
68
- end
69
- end
70
- end
@@ -1,55 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Tessa::ControllerHelpers do
4
- let(:controller) {
5
- Class.new do
6
- attr_writer :session
7
-
8
- def session
9
- @session ||= {}
10
- end
11
-
12
- end.tap { |c| c.send :include, described_class }
13
- }
14
- subject(:instance) { controller.new }
15
-
16
- describe "#tessa_upload_asset_ids" do
17
- it "returns the value of session[:tessa_upload_asset_ids]" do
18
- instance.session = { tessa_upload_asset_ids: :value }
19
- expect(instance.tessa_upload_asset_ids).to eq(:value)
20
- end
21
-
22
- it "sets and returns session[:tessa_upload_asset_ids] to an empty array if nil" do
23
- array = instance.tessa_upload_asset_ids
24
- expect(array).to eq([])
25
- array << 123
26
- expect(instance.tessa_upload_asset_ids).to eq(array)
27
- end
28
- end
29
-
30
- describe "#params_for_asset" do
31
- it "returns a Tessa::AssetChangeSet" do
32
- expect(instance.params_for_asset({})).to be_a(Tessa::AssetChangeSet)
33
- end
34
-
35
- it "sets the value of changes to the argument passed" do
36
- changes = [Tessa::AssetChange.new(id: 1)]
37
- expect(instance.params_for_asset(changes).changes).to eq(changes)
38
- end
39
-
40
- it "sets the scoped_ids to the value of tessa_upload_asset_ids" do
41
- scoped_ids = [1, 2, 3]
42
- instance.session[:tessa_upload_asset_ids] = scoped_ids
43
- expect(instance.params_for_asset([]).scoped_ids).to eq(scoped_ids)
44
- end
45
-
46
- it "ensures a unique array" do
47
- scoped_ids = [1]
48
- instance.session[:tessa_upload_asset_ids] = scoped_ids
49
- set = instance.params_for_asset([])
50
- set.scoped_ids << 2
51
- expect(scoped_ids).to eq([1])
52
- end
53
- end
54
-
55
- end
@@ -1,247 +0,0 @@
1
- require 'rails_helper'
2
-
3
- require 'tessa/jobs/migrate_assets_job'
4
-
5
- RSpec.describe Tessa::MigrateAssetsJob do
6
- it 'does nothing if no db rows' do
7
-
8
- expect {
9
- subject.perform
10
- }.to_not change { ActiveStorage::Attachment.count }
11
- end
12
-
13
- it 'creates attachments for old tessa assets' do
14
- allow(Tessa::Asset).to receive(:find)
15
- .with(1)
16
- .and_return(
17
- Tessa::Asset.new(id: 1,
18
- meta: { name: 'README.md' },
19
- private_download_url: 'https://test.com/README.md')
20
- )
21
-
22
- allow(Tessa::Asset).to receive(:find)
23
- .with(2)
24
- .and_return(
25
- Tessa::Asset.new(id: 2,
26
- meta: { name: 'LICENSE.txt' },
27
- private_download_url: 'https://test.com/LICENSE.txt'),
28
- )
29
-
30
- stub_request(:get, 'https://test.com/README.md')
31
- .to_return(body: File.new('README.md'))
32
- stub_request(:get, 'https://test.com/LICENSE.txt')
33
- .to_return(body: File.new('LICENSE.txt'))
34
-
35
- # DB models with those
36
- models = [
37
- SingleAssetModel.create!(avatar_id: 1),
38
- SingleAssetModel.create!(avatar_id: 2)
39
- ]
40
-
41
- expect {
42
- subject.perform
43
- }.to change { ActiveStorage::Attachment.count }.by(2)
44
-
45
- models.each do |m|
46
- expect(m.reload.avatar_id).to eq(m.avatar.key)
47
- # Now it's in activestorage
48
- expect(m.avatar.public_url).to start_with(
49
- 'https://www.example.com/rails/active_storage/blobs/')
50
- end
51
-
52
- expect(SingleAssetModel.where.not('avatar_id' => nil).count)
53
- .to eq(0)
54
- end
55
-
56
- it 'preserves ActiveStorage blobs' do
57
- allow(Tessa::Asset).to receive(:find)
58
- .with([1, 2])
59
- .and_return([
60
- Tessa::Asset.new(id: 1,
61
- meta: { name: 'README.md' },
62
- private_download_url: 'https://test.com/README.md'),
63
- Tessa::Asset.new(id: 2,
64
- meta: { name: 'LICENSE.txt' },
65
- private_download_url: 'https://test.com/LICENSE.txt'),
66
- ])
67
- stub_request(:get, 'https://test.com/README.md')
68
- .to_return(body: File.new('README.md'))
69
- stub_request(:get, 'https://test.com/LICENSE.txt')
70
- .to_return(body: File.new('LICENSE.txt'))
71
-
72
- file2 = Rack::Test::UploadedFile.new("LICENSE.txt")
73
-
74
- model = MultipleAssetModel.create!(
75
- # The Tessa DB column has the one asset
76
- another_place: [1, 2]
77
- )
78
- # But has already attached a second ActiveStorage blob
79
- ::ActiveStorage::Attached::Many.new("multiple_field", model, dependent: :purge_later)
80
- .attach(file2)
81
- model.save!
82
- attachment = model.multiple_field_attachments.first
83
-
84
- expect {
85
- subject.perform
86
- }.to change { ActiveStorage::Attachment.count }.by(2)
87
-
88
- model = model.reload
89
- # The IDs are now the keys of ActiveStorage objects
90
- expect(model.another_place).to eq(
91
- model.multiple_field.map(&:key))
92
- # preserves the existing attachment
93
- expect(model.multiple_field_attachments).to include(attachment)
94
- expect(model.another_place).to include(attachment.key)
95
-
96
- # all assets are in activestorage
97
- model.multiple_field.each do |blob|
98
- expect(blob.public_url).to start_with(
99
- 'https://www.example.com/rails/active_storage/blobs/')
100
- end
101
-
102
- # DB column is reset to nil
103
- expect(MultipleAssetModel.where.not('another_place' => nil).count)
104
- .to eq(0)
105
- end
106
-
107
- it 'Stops after hitting the batch size' do
108
- 1.upto(11).each do |i|
109
- asset = Tessa::Asset.new(id: i,
110
- meta: { name: 'README.md' },
111
- private_download_url: 'https://test.com/README.md')
112
- allow(Tessa::Asset).to receive(:find)
113
- .with(i)
114
- .and_return(asset)
115
- allow(Tessa::Asset).to receive(:find)
116
- .with([i])
117
- .and_return([asset])
118
- end
119
- stub_request(:get, 'https://test.com/README.md')
120
- .to_return(body: File.new('README.md'))
121
-
122
- # Mix of the two models...
123
- models =
124
- 1.upto(11).map do |i|
125
- if i % 2 == 0
126
- MultipleAssetModel.create!(another_place: [i])
127
- else
128
- SingleAssetModel.create!(avatar_id: i)
129
- end
130
- end
131
-
132
- final_state = nil
133
- final_options = nil
134
- dbl = double('set')
135
- expect(dbl).to receive(:perform_later) do |state, options|
136
- final_state = Marshal.load(state)
137
- final_options = options
138
- end
139
- expect(Tessa::MigrateAssetsJob).to receive(:set)
140
- .with(wait: 10.minutes)
141
- .and_return(dbl)
142
-
143
- expect {
144
- subject.perform
145
- }.to change { ActiveStorage::Attachment.count }.by(10)
146
-
147
- expect(final_state.fully_processed?).to be false
148
- expect(final_options).to eq({
149
- batch_size: 10,
150
- interval: 10.minutes.to_i
151
- })
152
- # One of the two models was fully processed
153
- expect(final_state.model_queue.count(&:fully_processed?))
154
- .to eq(1)
155
- end
156
-
157
- it 'Skips over Tessa errors' do
158
- 1.upto(11).each do |i|
159
- if i % 2 == 0
160
- allow(Tessa::Asset).to receive(:find)
161
- .with(i)
162
- .and_raise(Tessa::RequestFailed)
163
- next
164
- end
165
-
166
- allow(Tessa::Asset).to receive(:find)
167
- .with(i)
168
- .and_return(
169
- Tessa::Asset.new(id: i,
170
- meta: { name: 'README.md' },
171
- private_download_url: 'https://test.com/README.md')
172
- )
173
- end
174
- stub_request(:get, 'https://test.com/README.md')
175
- .to_return(body: File.new('README.md'))
176
-
177
- # Mix of the two models...
178
- models =
179
- 1.upto(11).map do |i|
180
- SingleAssetModel.create!(avatar_id: i)
181
- end
182
-
183
- final_state = nil
184
- final_options = nil
185
- dbl = double('set')
186
- expect(dbl).to receive(:perform_later) do |state, options|
187
- final_state = Marshal.load(state)
188
- final_options = options
189
- end
190
- expect(Tessa::MigrateAssetsJob).to receive(:set)
191
- .with(wait: 10.minutes)
192
- .and_return(dbl)
193
-
194
- expect {
195
- subject.perform
196
- }.to change { ActiveStorage::Attachment.count }.by(5)
197
-
198
- expect(final_state.fully_processed?).to be false
199
- field_state = final_state.next_model.next_field
200
- expect(field_state.offset).to eq(5)
201
- end
202
-
203
- it 'Resumes from marshalled state' do
204
-
205
- file = Rack::Test::UploadedFile.new('README.md')
206
-
207
- state = Tessa::MigrateAssetsJob::ProcessingState.initialize_from_models(
208
- [SingleAssetModel])
209
- field_state = state.model_queue
210
- .detect { |m| m.class_name == 'SingleAssetModel' }
211
- .field_queue
212
- .detect { |m| m.field_name == :avatar }
213
-
214
- 1.upto(10).each do |i|
215
- if i % 2 == 0
216
- # This one failed
217
- SingleAssetModel.create!(avatar_id: i).tap do |r|
218
- field_state.offset += 1
219
- end
220
- else
221
- # This one succeeded and is in ActiveStorage
222
- SingleAssetModel.create!(avatar: file).tap do |r|
223
- field_state.success_count += 1
224
- end
225
- end
226
- end
227
-
228
- # This one still needs to transition
229
- model = SingleAssetModel.create!(avatar_id: 11)
230
-
231
- asset = Tessa::Asset.new(id: 11,
232
- meta: { name: 'README.md' },
233
- private_download_url: 'https://test.com/README.md')
234
- allow(Tessa::Asset).to receive(:find)
235
- .with(11)
236
- .and_return(asset)
237
- stub_request(:get, 'https://test.com/README.md')
238
- .to_return(body: File.new('README.md'))
239
-
240
- # Doesn't reenqueue since we finished processing
241
- expect(Tessa::MigrateAssetsJob).to_not receive(:set)
242
-
243
- expect {
244
- subject.perform(Marshal.dump(state), { batch_size: 2, interval: 3 })
245
- }.to change { ActiveStorage::Attachment.count }.by(1)
246
- end
247
- end
@@ -1,72 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Tessa::Model::Field do
4
- subject(:field) { described_class.new(attrs) }
5
- let(:attrs) { {} }
6
-
7
- describe "#initialize" do
8
- context "with all fields set" do
9
- let(:attrs) {
10
- {
11
- model: :model,
12
- name: "name",
13
- multiple: true,
14
- id_field: "my_field",
15
- }
16
- }
17
-
18
- it "sets :model to attribute" do
19
- expect(field.model).to eq(:model)
20
- end
21
-
22
- it "sets :name to attribute" do
23
- expect(field.name).to eq("name")
24
- end
25
-
26
- it "sets :multiple to attribute" do
27
- expect(field.multiple).to eq(true)
28
- end
29
-
30
- it "sets :id_field to attribute" do
31
- expect(field.id_field).to eq("my_field")
32
- end
33
- end
34
-
35
- context "with no fields set" do
36
- it "defaults model to nil" do
37
- expect(field.model).to be_nil
38
- end
39
-
40
- it "defaults name to nil" do
41
- expect(field.name).to be_nil
42
- end
43
-
44
- it "defaults multiple to false" do
45
- expect(field.multiple).to eq(false)
46
- end
47
-
48
- context "when multiple true" do
49
- before do
50
- attrs[:name] = "my_name"
51
- attrs[:multiple] = false
52
- end
53
-
54
- it "defaults id_field to name + '_id'" do
55
- expect(field.id_field).to eq("my_name_id")
56
- end
57
- end
58
-
59
- context "when multiple false" do
60
- before do
61
- attrs[:name] = "my_name"
62
- attrs[:multiple] = true
63
- end
64
-
65
- it "defaults id_field to name + '_ids'" do
66
- expect(field.id_field).to eq("my_name_ids")
67
- end
68
- end
69
- end
70
- end
71
-
72
- end