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.
- checksums.yaml +4 -4
- data/README.md +11 -18
- data/app/assets/javascripts/tessa.esm.js +212 -173
- data/app/assets/javascripts/tessa.js +206 -167
- data/app/javascript/activestorage/file_checksum.ts +76 -0
- data/app/javascript/tessa/index.ts +264 -0
- data/app/javascript/tessa/types.ts +34 -0
- data/config/routes.rb +0 -1
- data/lib/tessa/simple_form/asset_input.rb +24 -25
- data/lib/tessa/version.rb +1 -1
- data/lib/tessa.rb +0 -80
- data/package.json +7 -2
- data/rollup.config.js +5 -5
- data/spec/dummy/app/models/single_asset_model.rb +1 -1
- data/spec/dummy/app/models/single_asset_model_form.rb +3 -5
- data/spec/dummy/bin/rails +2 -2
- data/spec/dummy/bin/rake +2 -2
- data/spec/dummy/bin/setup +14 -6
- data/spec/dummy/bin/yarn +9 -3
- data/spec/dummy/config/application.rb +11 -9
- data/spec/dummy/config/boot.rb +1 -1
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/environments/development.rb +34 -5
- data/spec/dummy/config/environments/production.rb +49 -10
- data/spec/dummy/config/environments/test.rb +28 -12
- data/spec/dummy/config/initializers/backtrace_silencers.rb +4 -3
- data/spec/dummy/config/initializers/content_security_policy.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +3 -1
- data/spec/dummy/config/initializers/new_framework_defaults_6_1.rb +67 -0
- data/spec/dummy/config/initializers/permissions_policy.rb +11 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +5 -0
- data/spec/dummy/config/locales/en.yml +1 -1
- data/spec/dummy/config/routes.rb +1 -1
- data/spec/dummy/config/storage.yml +31 -0
- data/spec/dummy/config.ru +2 -1
- data/spec/dummy/db/migrate/20230406194400_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
- data/spec/dummy/db/migrate/20230406194401_create_active_storage_variant_records.active_storage.rb +27 -0
- data/spec/dummy/db/schema.rb +15 -7
- data/tessa.gemspec +4 -5
- data/tsconfig.json +10 -0
- data/yarn.lock +74 -7
- metadata +36 -74
- data/app/javascript/activestorage/file_checksum.js +0 -53
- data/app/javascript/tessa/index.js.coffee +0 -183
- data/lib/tasks/tessa.rake +0 -18
- data/lib/tessa/active_storage/asset_wrapper.rb +0 -32
- data/lib/tessa/asset/failure.rb +0 -37
- data/lib/tessa/asset.rb +0 -47
- data/lib/tessa/asset_change.rb +0 -49
- data/lib/tessa/asset_change_set.rb +0 -49
- data/lib/tessa/config.rb +0 -16
- data/lib/tessa/controller_helpers.rb +0 -16
- data/lib/tessa/fake_connection.rb +0 -29
- data/lib/tessa/jobs/migrate_assets_job.rb +0 -222
- data/lib/tessa/model/dynamic_extensions.rb +0 -145
- data/lib/tessa/model/field.rb +0 -77
- data/lib/tessa/model.rb +0 -94
- data/lib/tessa/rack_upload_proxy.rb +0 -41
- data/lib/tessa/response_factory.rb +0 -15
- data/lib/tessa/upload/uploads_file.rb +0 -18
- data/lib/tessa/upload.rb +0 -31
- data/lib/tessa/view_helpers.rb +0 -23
- data/spec/dummy/app/models/multiple_asset_model.rb +0 -8
- data/spec/support/remote_call_macro.rb +0 -40
- data/spec/tessa/asset/failure_spec.rb +0 -48
- data/spec/tessa/asset_change_set_spec.rb +0 -198
- data/spec/tessa/asset_change_spec.rb +0 -86
- data/spec/tessa/asset_spec.rb +0 -196
- data/spec/tessa/config_spec.rb +0 -70
- data/spec/tessa/controller_helpers_spec.rb +0 -55
- data/spec/tessa/jobs/migrate_assets_job_spec.rb +0 -247
- data/spec/tessa/model_field_spec.rb +0 -72
- data/spec/tessa/model_spec.rb +0 -325
- data/spec/tessa/rack_upload_proxy_spec.rb +0 -83
- data/spec/tessa/upload/uploads_file_spec.rb +0 -72
- data/spec/tessa/upload_spec.rb +0 -125
- data/spec/tessa_spec.rb +0 -23
data/spec/tessa/model_spec.rb
DELETED
@@ -1,325 +0,0 @@
|
|
1
|
-
require 'rails_helper'
|
2
|
-
|
3
|
-
RSpec.describe Tessa::Model do
|
4
|
-
subject(:described_module) { described_class }
|
5
|
-
let(:model) {
|
6
|
-
SingleAssetModel
|
7
|
-
}
|
8
|
-
|
9
|
-
it { is_expected.to be_a(Module) }
|
10
|
-
|
11
|
-
describe "::asset" do
|
12
|
-
it "creates ModelField and sets it by name to @tessa_fields" do
|
13
|
-
expect(model.tessa_fields[:avatar]).to be_a(Tessa::Model::Field)
|
14
|
-
end
|
15
|
-
|
16
|
-
context "with a field named :avatar" do
|
17
|
-
subject(:instance) { model.new }
|
18
|
-
|
19
|
-
it "creates an #avatar method" do
|
20
|
-
expect(instance).to respond_to(:avatar)
|
21
|
-
end
|
22
|
-
|
23
|
-
it "creates an #avatar= method" do
|
24
|
-
expect(instance).to respond_to(:avatar=)
|
25
|
-
end
|
26
|
-
|
27
|
-
it "allows overriding and calling super" do
|
28
|
-
model.class_eval do
|
29
|
-
def avatar
|
30
|
-
@override_test = true
|
31
|
-
super
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
instance.avatar
|
36
|
-
expect(instance.instance_variable_get(:@override_test)).to eq(true)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context "with customized field" do
|
41
|
-
let(:model) {
|
42
|
-
MultipleAssetModel
|
43
|
-
}
|
44
|
-
let(:instance) { model.new(another_place: []) }
|
45
|
-
|
46
|
-
it "sets all attributes on ModelField properly" do
|
47
|
-
field = model.tessa_fields[:multiple_field]
|
48
|
-
expect(field.name).to eq("multiple_field")
|
49
|
-
expect(field.multiple).to eq(true)
|
50
|
-
expect(field.id_field).to eq("another_place")
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
context "with inheritance hierarchy" do
|
55
|
-
let(:submodel) {
|
56
|
-
Class.new(model) do
|
57
|
-
asset :field2
|
58
|
-
end
|
59
|
-
}
|
60
|
-
|
61
|
-
it "submodel has its own list of fields" do
|
62
|
-
expect(submodel.tessa_fields.keys).to eq([:avatar, :field2])
|
63
|
-
end
|
64
|
-
|
65
|
-
it "does not alter parent class fields" do
|
66
|
-
expect(model.tessa_fields.keys).to eq([:avatar])
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
context "on a form object" do
|
71
|
-
let(:model) {
|
72
|
-
SingleAssetModelForm
|
73
|
-
}
|
74
|
-
subject(:instance) { model.new }
|
75
|
-
|
76
|
-
it "creates an #avatar method" do
|
77
|
-
expect(instance).to respond_to(:avatar)
|
78
|
-
end
|
79
|
-
|
80
|
-
it "creates an #avatar= method" do
|
81
|
-
expect(instance).to respond_to(:avatar=)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
describe "#asset_getter" do
|
87
|
-
let(:instance) { model.new }
|
88
|
-
|
89
|
-
context "with a multiple typed field" do
|
90
|
-
let(:model) {
|
91
|
-
MultipleAssetModel
|
92
|
-
}
|
93
|
-
let(:instance) { model.new(another_place: []) }
|
94
|
-
subject(:getter) { instance.multiple_field }
|
95
|
-
|
96
|
-
it "No longer calls Tessa::Asset#find" do
|
97
|
-
instance.another_place = [1, 2, 3]
|
98
|
-
expect(Tessa::Asset).to_not receive(:find)
|
99
|
-
expect(getter).to eq([])
|
100
|
-
end
|
101
|
-
|
102
|
-
context "with no values" do
|
103
|
-
it "does not call find" do
|
104
|
-
instance.another_place = []
|
105
|
-
expect(Tessa::Asset).not_to receive(:find)
|
106
|
-
expect(instance.multiple_field).to eq([])
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
context "with a singular typed field" do
|
112
|
-
let(:model) {
|
113
|
-
SingleAssetModel
|
114
|
-
}
|
115
|
-
subject(:getter) { instance.avatar }
|
116
|
-
|
117
|
-
it "No longer calls Tessa::Asset#find" do
|
118
|
-
instance.avatar_id = 1
|
119
|
-
expect(Tessa::Asset).to_not receive(:find)
|
120
|
-
expect(getter).to eq(nil)
|
121
|
-
end
|
122
|
-
|
123
|
-
it "wraps ActiveStorage uploads with AssetWrapper" do
|
124
|
-
file = Rack::Test::UploadedFile.new("README.md")
|
125
|
-
instance.avatar = file
|
126
|
-
|
127
|
-
asset = instance.avatar
|
128
|
-
expect(asset).to be_a(Tessa::ActiveStorage::AssetWrapper)
|
129
|
-
# This goes to the blobs URL, which then redirects to the backend service URL
|
130
|
-
expect(asset.public_url).to start_with('https://www.example.com/rails/active_storage/blobs/')
|
131
|
-
# This is a direct download to the service URL (in test mode that is "disk")
|
132
|
-
expect(asset.private_url).to start_with('https://www.example.com/rails/active_storage/disk/')
|
133
|
-
expect(asset.private_download_url).to start_with('https://www.example.com/rails/active_storage/disk/')
|
134
|
-
expect(asset.private_download_url).to include('&disposition=attachment')
|
135
|
-
end
|
136
|
-
|
137
|
-
context "with nil value" do
|
138
|
-
it "does not call find" do
|
139
|
-
instance.avatar_id = nil
|
140
|
-
expect(Tessa::Asset).not_to receive(:find)
|
141
|
-
expect(instance.avatar).to be_nil
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
context "on a form object" do
|
147
|
-
let(:model) {
|
148
|
-
SingleAssetModelForm
|
149
|
-
}
|
150
|
-
subject(:getter) { instance.avatar }
|
151
|
-
|
152
|
-
it 'returns nil when empty' do
|
153
|
-
expect(getter).to be_nil
|
154
|
-
end
|
155
|
-
|
156
|
-
it 'returns assigned upload object' do
|
157
|
-
file = Rack::Test::UploadedFile.new("README.md")
|
158
|
-
instance.avatar = file
|
159
|
-
expect(getter).to eq(file)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
describe "#asset_setter" do
|
165
|
-
let(:instance) { model.new }
|
166
|
-
|
167
|
-
context "with a singular typed field" do
|
168
|
-
let(:model) {
|
169
|
-
SingleAssetModel
|
170
|
-
}
|
171
|
-
subject(:getter) { instance.avatar }
|
172
|
-
let(:file) {
|
173
|
-
Rack::Test::UploadedFile.new("README.md")
|
174
|
-
}
|
175
|
-
|
176
|
-
it 'attaches uploaded file' do
|
177
|
-
instance.avatar = file
|
178
|
-
|
179
|
-
expect(getter.name).to eq('avatar')
|
180
|
-
expect(getter.filename).to eq('README.md')
|
181
|
-
expect(getter.content_type).to eq('text/plain')
|
182
|
-
expect(getter.service_url)
|
183
|
-
.to start_with('https://www.example.com/rails/active_storage/disk/')
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'sets the ID to be the ActiveStorage key' do
|
187
|
-
instance.avatar = file
|
188
|
-
|
189
|
-
expect(instance.avatar_id).to eq(instance.avatar_attachment.key)
|
190
|
-
end
|
191
|
-
|
192
|
-
it 'sets the ID in the attributes' do
|
193
|
-
instance.avatar = file
|
194
|
-
|
195
|
-
expect(instance.attributes['avatar_id']).to eq(instance.avatar_attachment.key)
|
196
|
-
end
|
197
|
-
|
198
|
-
it 'attaches signed ID from Tessa::AssetChangeSet' do
|
199
|
-
blob = ::ActiveStorage::Blob.create_before_direct_upload!({
|
200
|
-
filename: 'README.md',
|
201
|
-
byte_size: file.size,
|
202
|
-
content_type: file.content_type,
|
203
|
-
checksum: '1234'
|
204
|
-
})
|
205
|
-
|
206
|
-
changeset = Tessa::AssetChangeSet.new(
|
207
|
-
changes: [{ 'id' => blob.signed_id, 'action' => 'add' }]
|
208
|
-
)
|
209
|
-
instance.avatar = changeset
|
210
|
-
|
211
|
-
expect(instance.avatar_id).to eq(instance.avatar_attachment.key)
|
212
|
-
end
|
213
|
-
|
214
|
-
it 'does nothing when "add"ing an existing blob' do
|
215
|
-
# Before this HTTP POST, we've previously uploaded this file
|
216
|
-
instance.avatar = file
|
217
|
-
|
218
|
-
# In this HTTP POST, we re-upload the 'add' action with the same ID
|
219
|
-
changeset = Tessa::AssetChangeSet.new(
|
220
|
-
changes: [{ 'id' => instance.avatar_attachment.key, 'action' => 'add' }]
|
221
|
-
)
|
222
|
-
|
223
|
-
# We expect that we're not going to detatch the existing attachment
|
224
|
-
expect(instance.avatar_attachment).to_not receive(:destroy)
|
225
|
-
|
226
|
-
# act
|
227
|
-
instance.avatar = changeset
|
228
|
-
|
229
|
-
expect(instance.avatar_id).to eq(instance.avatar_attachment.key)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
context "with a multiple typed field" do
|
234
|
-
let(:model) {
|
235
|
-
MultipleAssetModel
|
236
|
-
}
|
237
|
-
let(:instance) { model.new(another_place: []) }
|
238
|
-
let(:file) {
|
239
|
-
Rack::Test::UploadedFile.new("README.md")
|
240
|
-
}
|
241
|
-
let(:file2) {
|
242
|
-
Rack::Test::UploadedFile.new("LICENSE.txt")
|
243
|
-
}
|
244
|
-
|
245
|
-
it 'attaches uploaded files' do
|
246
|
-
instance.multiple_field = [file, file2]
|
247
|
-
|
248
|
-
expect(instance.multiple_field[0].name).to eq('multiple_field')
|
249
|
-
expect(instance.multiple_field[0].filename).to eq('README.md')
|
250
|
-
expect(instance.multiple_field[0].content_type).to eq('text/plain')
|
251
|
-
expect(instance.multiple_field[0].service_url)
|
252
|
-
.to start_with('https://www.example.com/rails/active_storage/disk/')
|
253
|
-
expect(instance.multiple_field[1].name).to eq('multiple_field')
|
254
|
-
expect(instance.multiple_field[1].filename).to eq('LICENSE.txt')
|
255
|
-
expect(instance.multiple_field[1].content_type).to eq('text/plain')
|
256
|
-
expect(instance.multiple_field[1].service_url)
|
257
|
-
.to start_with('https://www.example.com/rails/active_storage/disk/')
|
258
|
-
end
|
259
|
-
|
260
|
-
it 'sets the ID to be the ActiveStorage key' do
|
261
|
-
instance.multiple_field = [file, file2]
|
262
|
-
|
263
|
-
expect(instance.another_place).to eq(instance.multiple_field_attachments.map(&:key))
|
264
|
-
end
|
265
|
-
|
266
|
-
it 'sets the ID in the attributes' do
|
267
|
-
instance.multiple_field = [file, file2]
|
268
|
-
|
269
|
-
expect(instance.attributes['another_place']).to eq(instance.multiple_field_attachments.map(&:key))
|
270
|
-
end
|
271
|
-
|
272
|
-
it 'attaches signed ID from Tessa::AssetChangeSet' do
|
273
|
-
blob = ::ActiveStorage::Blob.create_before_direct_upload!({
|
274
|
-
filename: 'README.md',
|
275
|
-
byte_size: file.size,
|
276
|
-
content_type: file.content_type,
|
277
|
-
checksum: '1234'
|
278
|
-
})
|
279
|
-
blob2 = ::ActiveStorage::Blob.create_before_direct_upload!({
|
280
|
-
filename: "LICENSE.txt",
|
281
|
-
byte_size: file2.size,
|
282
|
-
content_type: file2.content_type,
|
283
|
-
checksum: '5678'
|
284
|
-
})
|
285
|
-
|
286
|
-
changeset = Tessa::AssetChangeSet.new(
|
287
|
-
changes: [
|
288
|
-
{ 'id' => blob.signed_id, 'action' => 'add' },
|
289
|
-
{ 'id' => blob2.signed_id, 'action' => 'add' },
|
290
|
-
]
|
291
|
-
)
|
292
|
-
instance.multiple_field = changeset
|
293
|
-
|
294
|
-
expect(instance.another_place).to eq([
|
295
|
-
blob.key,
|
296
|
-
blob2.key
|
297
|
-
])
|
298
|
-
end
|
299
|
-
|
300
|
-
it 'does nothing when "add"ing an existing blob' do
|
301
|
-
# Before this HTTP POST, we've previously uploaded these files
|
302
|
-
instance.multiple_field = [file, file2]
|
303
|
-
keys = instance.multiple_field_attachments.map(&:key)
|
304
|
-
|
305
|
-
# In this HTTP POST, we re-upload the 'add' action with the same ID
|
306
|
-
changeset = Tessa::AssetChangeSet.new(
|
307
|
-
changes: [
|
308
|
-
{ 'id' => keys[0], 'action' => 'add' },
|
309
|
-
{ 'id' => keys[1], 'action' => 'add' },
|
310
|
-
]
|
311
|
-
)
|
312
|
-
|
313
|
-
# We expect that we're not going to detatch the existing attachment
|
314
|
-
instance.multiple_field_attachments.each do |a|
|
315
|
-
expect(a).to_not receive(:destroy)
|
316
|
-
end
|
317
|
-
|
318
|
-
# act
|
319
|
-
instance.multiple_field = changeset
|
320
|
-
|
321
|
-
expect(instance.another_place).to eq(keys)
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe Tessa::RackUploadProxy do
|
4
|
-
Result = Struct.new(:status, :headers, :body) do
|
5
|
-
def json
|
6
|
-
JSON.parse body.first
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
subject(:result) { Result.new *described_class.call(env) }
|
11
|
-
let(:env) {
|
12
|
-
{
|
13
|
-
"rack.request.form_hash" => params,
|
14
|
-
"rack.session" => session,
|
15
|
-
}
|
16
|
-
}
|
17
|
-
let(:params) { {} }
|
18
|
-
let(:session) { {} }
|
19
|
-
|
20
|
-
let(:blob) { ActiveStorage::Blob.last }
|
21
|
-
|
22
|
-
before do
|
23
|
-
allow(ActiveStorage.verifier).to receive(:generate)
|
24
|
-
.and_return('some-consistent-token')
|
25
|
-
end
|
26
|
-
|
27
|
-
shared_examples_for "proper json return" do
|
28
|
-
it "returns asset_id" do
|
29
|
-
expect(result.json['asset_id']).to eq(blob.signed_id)
|
30
|
-
end
|
31
|
-
|
32
|
-
it "returns upload_url" do
|
33
|
-
expect(result.json['upload_url']).to eq('https://www.example.com/rails/active_storage/disk/some-consistent-token')
|
34
|
-
end
|
35
|
-
|
36
|
-
it "returns upload_method" do
|
37
|
-
expect(result.json['upload_method']).to eq('PUT')
|
38
|
-
end
|
39
|
-
|
40
|
-
it "returns upload_method" do
|
41
|
-
expect(result.json['upload_headers']).to eq(blob.service_headers_for_direct_upload)
|
42
|
-
end
|
43
|
-
|
44
|
-
it "returns a 200 response" do
|
45
|
-
expect(result.status).to eq(200)
|
46
|
-
end
|
47
|
-
|
48
|
-
it "sets the mime type to application/json" do
|
49
|
-
expect(result.headers).to include("Content-Type" => "application/json")
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
context "with no params and no session" do
|
54
|
-
it "raises a bad request error" do
|
55
|
-
expect(result.status).to eq(400)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
context "with params" do
|
60
|
-
let(:params) {
|
61
|
-
{
|
62
|
-
"name" => "my-name",
|
63
|
-
"size" => 456,
|
64
|
-
"mime_type" => "plain/text",
|
65
|
-
"checksum" => '1234'
|
66
|
-
}
|
67
|
-
}
|
68
|
-
|
69
|
-
it "creates the ActiveStorage blob" do
|
70
|
-
expect {
|
71
|
-
described_class.call(env)
|
72
|
-
}.to change { ActiveStorage::Blob.count }.by(1)
|
73
|
-
|
74
|
-
expect(blob.filename).to eq('my-name')
|
75
|
-
expect(blob.byte_size).to eq(456)
|
76
|
-
expect(blob.content_type).to eq('plain/text')
|
77
|
-
expect(blob.checksum).to eq('1234')
|
78
|
-
end
|
79
|
-
|
80
|
-
it_behaves_like "proper json return"
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe Tessa::Upload::UploadsFile do
|
4
|
-
describe "#initialize" do
|
5
|
-
it "requires an upload and sets it to attribute" do
|
6
|
-
expect { described_class.new }.to raise_error(ArgumentError)
|
7
|
-
obj = described_class.new(upload: :upload)
|
8
|
-
expect(obj.upload).to eq(:upload)
|
9
|
-
end
|
10
|
-
|
11
|
-
it "optionally takes a connection" do
|
12
|
-
obj = described_class.new(upload: :upload, connection: :conn)
|
13
|
-
expect(obj.connection).to eq(:conn)
|
14
|
-
end
|
15
|
-
|
16
|
-
it "defaults connection to empty Faraday connection" do
|
17
|
-
expect(described_class).to receive(:connection_factory).and_return(:foo)
|
18
|
-
obj = described_class.new(upload: :upload)
|
19
|
-
expect(obj.connection).to eq(:foo)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "#call" do
|
24
|
-
let(:upload) {
|
25
|
-
instance_double(
|
26
|
-
Tessa::Upload,
|
27
|
-
upload_url: "http://upload/path?arg=1",
|
28
|
-
upload_method: "post"
|
29
|
-
)
|
30
|
-
}
|
31
|
-
let(:connection) {
|
32
|
-
Faraday.new { |f| f.adapter :test, stubs }
|
33
|
-
}
|
34
|
-
subject(:task) { described_class.new(upload: upload, connection: connection) }
|
35
|
-
|
36
|
-
context "uploads file successfully" do
|
37
|
-
let(:stubs) {
|
38
|
-
Faraday::Adapter::Test::Stubs.new do |stub|
|
39
|
-
stub.post("http://upload/path?arg=1") { |env|
|
40
|
-
[200, {}, '']
|
41
|
-
}
|
42
|
-
end
|
43
|
-
}
|
44
|
-
|
45
|
-
it "calls the upload_url with upload_method HTTP method" do
|
46
|
-
file = Tempfile.new("test")
|
47
|
-
file.write "hello there"
|
48
|
-
file.close
|
49
|
-
expect(connection).to receive(:post).with("http://upload/path?arg=1", "hello there").and_call_original
|
50
|
-
expect(task.call(file.path)).to be_truthy
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
context "uploads file successfully" do
|
55
|
-
let(:stubs) {
|
56
|
-
Faraday::Adapter::Test::Stubs.new do |stub|
|
57
|
-
stub.post("http://upload/path?arg=1") { |env|
|
58
|
-
[500, {}, '']
|
59
|
-
}
|
60
|
-
end
|
61
|
-
}
|
62
|
-
|
63
|
-
it "calls the upload_url with upload_method HTTP method" do
|
64
|
-
file = Tempfile.new("test")
|
65
|
-
file.write "hello there"
|
66
|
-
file.close
|
67
|
-
expect(connection).to receive(:post).with("http://upload/path?arg=1", "hello there").and_call_original
|
68
|
-
expect(task.call(file.path)).to be_falsey
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
data/spec/tessa/upload_spec.rb
DELETED
@@ -1,125 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe Tessa::Upload do
|
4
|
-
subject(:upload) { described_class.new(args) }
|
5
|
-
let(:args) {
|
6
|
-
{
|
7
|
-
upload_url: "/upload",
|
8
|
-
upload_method: "put",
|
9
|
-
asset_id: 123,
|
10
|
-
}
|
11
|
-
}
|
12
|
-
|
13
|
-
describe "#initialize" do
|
14
|
-
context "with all arguments" do
|
15
|
-
it "sets upload_url to attribute" do
|
16
|
-
expect(upload.upload_url).to eq(args[:upload_url])
|
17
|
-
end
|
18
|
-
|
19
|
-
it "sets upload_method to attribute" do
|
20
|
-
expect(upload.upload_method).to eq(args[:upload_method])
|
21
|
-
end
|
22
|
-
|
23
|
-
it "sets asset_id to attribute" do
|
24
|
-
expect(upload.asset_id).to eq(args[:asset_id])
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe "#upload_file" do
|
30
|
-
subject(:upload) { described_class.new }
|
31
|
-
let(:task) { instance_double(described_class::UploadsFile) }
|
32
|
-
|
33
|
-
before :each do
|
34
|
-
allow(described_class::UploadsFile).to receive(:new).and_return(task)
|
35
|
-
allow(task).to receive(:call)
|
36
|
-
allow(Tessa::Asset).to receive(:new).and_return(instance_spy(Tessa::Asset))
|
37
|
-
end
|
38
|
-
|
39
|
-
it "initializes UploadsFile with self and passes argument to call" do
|
40
|
-
expect(task).to receive(:call).with(:file)
|
41
|
-
expect(described_class::UploadsFile).to receive(:new).with(upload: upload).and_return(task)
|
42
|
-
upload.upload_file(:file)
|
43
|
-
end
|
44
|
-
|
45
|
-
context "with a successful upload" do
|
46
|
-
before :each do
|
47
|
-
allow(task).to receive(:call).and_return(true)
|
48
|
-
end
|
49
|
-
|
50
|
-
it "updates the asset to complete state and returns asset" do
|
51
|
-
upload.asset_id = 123
|
52
|
-
asset = Tessa::Asset.new(id: 123)
|
53
|
-
expect(Tessa::Asset).to receive(:new).with(id: 123).and_return(asset)
|
54
|
-
expect(asset).to receive(:complete!).and_return(:asset)
|
55
|
-
expect(upload.upload_file(:file)).to eq(:asset)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
context "with a failed upload" do
|
60
|
-
before :each do
|
61
|
-
allow(task).to receive(:call).and_return(false)
|
62
|
-
end
|
63
|
-
|
64
|
-
it "updates the asset to canceled state and returns false" do
|
65
|
-
upload.asset_id = 123
|
66
|
-
asset = Tessa::Asset.new(id: 123)
|
67
|
-
expect(Tessa::Asset).to receive(:new).with(id: 123).and_return(asset)
|
68
|
-
expect(asset).to receive(:cancel!).and_return(:asset)
|
69
|
-
expect(upload.upload_file(:file)).to eq(false)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
describe ".create" do
|
75
|
-
subject(:call) { described_class.create(call_args) }
|
76
|
-
|
77
|
-
include_examples "remote call macro", :post, "/uploads", Tessa::Upload
|
78
|
-
|
79
|
-
context "with a full response" do
|
80
|
-
let(:remote_response) { args }
|
81
|
-
|
82
|
-
it "returns a new object initialized with the response" do
|
83
|
-
upload = described_class.create(connection: connection)
|
84
|
-
expect(upload.asset_id).to eq(args[:asset_id])
|
85
|
-
expect(upload.upload_url).to eq(args[:upload_url])
|
86
|
-
expect(upload.upload_method).to eq(args[:upload_method])
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
describe ":strategy param" do
|
91
|
-
it "defaults to config.strategy" do
|
92
|
-
expect(Tessa.config).to receive(:strategy).and_return(:my_default)
|
93
|
-
expect_post_with_hash_including(strategy: :my_default)
|
94
|
-
described_class.create(connection: connection)
|
95
|
-
end
|
96
|
-
|
97
|
-
it "overrides with :strategy argument" do
|
98
|
-
expect_post_with_hash_including(strategy: :my_default)
|
99
|
-
described_class.create(connection: connection, strategy: :my_default)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
it "sets :name param from argument" do
|
104
|
-
expect_post_with_hash_including(name: "my-file.txt")
|
105
|
-
described_class.create(connection: connection, name: "my-file.txt")
|
106
|
-
end
|
107
|
-
|
108
|
-
it "sets :size param from argument" do
|
109
|
-
expect_post_with_hash_including(size: 12345)
|
110
|
-
described_class.create(connection: connection, size: 12345)
|
111
|
-
end
|
112
|
-
|
113
|
-
it "sets :mime_type param from argument" do
|
114
|
-
expect_post_with_hash_including(mime_type: "text/plain")
|
115
|
-
described_class.create(connection: connection, mime_type: "text/plain")
|
116
|
-
end
|
117
|
-
|
118
|
-
def expect_post_with_hash_including(expected)
|
119
|
-
expect(connection).to receive(:post)
|
120
|
-
.with("/uploads", hash_including(expected))
|
121
|
-
.and_call_original
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|
data/spec/tessa_spec.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'rails_helper'
|
2
|
-
|
3
|
-
RSpec.describe Tessa do
|
4
|
-
|
5
|
-
describe '#find_assets' do
|
6
|
-
it 'returns AssetFailure for singular asset' do
|
7
|
-
result = Tessa.find_assets(1)
|
8
|
-
|
9
|
-
expect(result).to be_a(Tessa::Asset::Failure)
|
10
|
-
expect(result.message).to eq("The service is unavailable at this time.")
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'returns AssetFailure array for multiple assets' do
|
14
|
-
result = Tessa.find_assets([1, 2, 3])
|
15
|
-
|
16
|
-
expect(result.count).to eq(3)
|
17
|
-
result.each do |r|
|
18
|
-
expect(r).to be_a(Tessa::Asset::Failure)
|
19
|
-
expect(r.message).to eq("The service is unavailable at this time.")
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|