trailblazer 1.0.0.rc2 → 1.0.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.
- checksums.yaml +4 -4
- data/CHANGES.md +2 -1
- data/Rakefile +3 -16
- data/lib/trailblazer/autoloading.rb +0 -1
- data/lib/trailblazer/operation.rb +1 -6
- data/lib/trailblazer/version.rb +1 -1
- data/test/operation/dsl/representer_test.rb +0 -1
- data/test/test_helper.rb +0 -55
- data/trailblazer.gemspec +2 -5
- metadata +7 -92
- data/lib/trailblazer/operation/controller/active_record.rb +0 -16
- data/lib/trailblazer/operation/responder.rb +0 -23
- data/lib/trailblazer/operation/worker.rb +0 -111
- data/test/fixtures/apotomo.png +0 -0
- data/test/fixtures/cells.png +0 -0
- data/test/rails/__respond_test.rb +0 -20
- data/test/rails/controller_test.rb +0 -159
- data/test/rails/endpoint_test.rb +0 -46
- data/test/rails/fake_app/app-cells/.gitkeep +0 -0
- data/test/rails/fake_app/cells.rb +0 -21
- data/test/rails/fake_app/config.rb +0 -3
- data/test/rails/fake_app/controllers.rb +0 -140
- data/test/rails/fake_app/models.rb +0 -34
- data/test/rails/fake_app/rails_app.rb +0 -78
- data/test/rails/fake_app/song/operations.rb +0 -144
- data/test/rails/fake_app/views/bands/index.html.erb +0 -1
- data/test/rails/fake_app/views/songs/another_view.html.erb +0 -2
- data/test/rails/fake_app/views/songs/new.html.erb +0 -1
- data/test/rails/respond_test.rb +0 -95
- data/test/rails/test_helper.rb +0 -9
- data/test/responder_test.rb +0 -75
- data/test/uploaded_file_test.rb +0 -85
- data/test/worker_test.rb +0 -124
@@ -1,144 +0,0 @@
|
|
1
|
-
require 'trailblazer/autoloading'
|
2
|
-
|
3
|
-
class Song < ActiveRecord::Base
|
4
|
-
class Create < Trailblazer::Operation
|
5
|
-
include Model
|
6
|
-
include Responder
|
7
|
-
model Song, :create
|
8
|
-
|
9
|
-
|
10
|
-
contract do
|
11
|
-
property :title, validates: {presence: true}
|
12
|
-
property :length
|
13
|
-
end
|
14
|
-
|
15
|
-
def process(params)
|
16
|
-
validate(params[:song]) do
|
17
|
-
contract.save
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
class Json < Create
|
23
|
-
def process(params)
|
24
|
-
@model = Song.create(JSON.parse(params[:song]))
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
class Delete < Create
|
31
|
-
action :find
|
32
|
-
|
33
|
-
def process(params)
|
34
|
-
model.destroy
|
35
|
-
self
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class Band < ActiveRecord::Base
|
41
|
-
class Create < Trailblazer::Operation
|
42
|
-
include Model, Responder#, Representer
|
43
|
-
model Band, :create
|
44
|
-
|
45
|
-
contract do
|
46
|
-
include Reform::Form::ActiveModel
|
47
|
-
model Band
|
48
|
-
|
49
|
-
property :name, validates: {presence: true}
|
50
|
-
property :locality, prepopulator: ->(*) { self.locality = "Sydney" }
|
51
|
-
|
52
|
-
# class: Song #=> always create new song
|
53
|
-
# instance: { Song.find(params[:id]) or Song.new } # same as find_or_create ?
|
54
|
-
# this is what i want:
|
55
|
-
# maybe make populate_if_empty a representable feature?
|
56
|
-
collection :songs, populate_if_empty: Song do
|
57
|
-
property :title
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def process(params)
|
62
|
-
validate(params[:band]) do
|
63
|
-
contract.save
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
require "representable/json"
|
68
|
-
class JSON < self
|
69
|
-
include Representer
|
70
|
-
|
71
|
-
representer do
|
72
|
-
collection :songs, inherit: true, render_empty: false # tested in ControllerPresentTest.
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
class Admin < self
|
77
|
-
def process(params)
|
78
|
-
res = super
|
79
|
-
model.update_attribute :name, "#{model.name} [ADMIN]"
|
80
|
-
res
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# TODO: wait for uber 0.0.10 and @dutow.
|
85
|
-
# builds -> (params) do
|
86
|
-
# return JSON if params[:format] == "json"
|
87
|
-
# return Admin if params[:admin]
|
88
|
-
# end
|
89
|
-
builds do |params|
|
90
|
-
if params[:format] == "json"
|
91
|
-
JSON
|
92
|
-
elsif params[:admin]
|
93
|
-
Admin
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
class Update < Create
|
99
|
-
action :update
|
100
|
-
|
101
|
-
# TODO: infer stuff per default.
|
102
|
-
class JSON < self
|
103
|
-
include Representer
|
104
|
-
self.contract_class = Create::JSON.contract_class
|
105
|
-
self.representer_class = Create::JSON.representer_class
|
106
|
-
end
|
107
|
-
|
108
|
-
builds do |params|
|
109
|
-
JSON if params[:format] == "json"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
class Index < Trailblazer::Operation
|
114
|
-
include Collection
|
115
|
-
|
116
|
-
def model!(params)
|
117
|
-
Band.all
|
118
|
-
end
|
119
|
-
|
120
|
-
builds do |params|
|
121
|
-
JSON if params[:format] == "json"
|
122
|
-
end
|
123
|
-
|
124
|
-
class JSON < self
|
125
|
-
include Representer
|
126
|
-
|
127
|
-
module BandRepresenter
|
128
|
-
include Representable::JSON
|
129
|
-
property :name
|
130
|
-
property :locality
|
131
|
-
end
|
132
|
-
|
133
|
-
self.representer_class = BandRepresenter
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
class Tenant < ActiveRecord::Base
|
139
|
-
class Show < Trailblazer::Operation
|
140
|
-
include Model
|
141
|
-
model Tenant, :update
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
@@ -1 +0,0 @@
|
|
1
|
-
bands/index.html: <% @collection.each do |element| %><%= "#{element.name} " %><% end %>
|
@@ -1 +0,0 @@
|
|
1
|
-
<%= @form.errors.to_s %>
|
data/test/rails/respond_test.rb
DELETED
@@ -1,95 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class ResponderRespondTest < ActionController::TestCase
|
4
|
-
tests SongsController
|
5
|
-
|
6
|
-
# HTML
|
7
|
-
# #respond Create [valid]
|
8
|
-
test "Create [html/valid]" do
|
9
|
-
post :create, {song: {title: "You're Going Down"}}
|
10
|
-
assert_redirected_to song_path(Song.last)
|
11
|
-
end
|
12
|
-
|
13
|
-
test "Create [html/valid/location]" do
|
14
|
-
post :other_create, {song: {title: "You're Going Down"}}
|
15
|
-
assert_redirected_to other_create_songs_path
|
16
|
-
end
|
17
|
-
|
18
|
-
test "Create [html/invalid]" do
|
19
|
-
post :create, {song: {title: ""}}
|
20
|
-
assert_response 200
|
21
|
-
assert_equal @response.body, "{:title=>["can't be blank"]}"
|
22
|
-
end
|
23
|
-
|
24
|
-
test "Create [html/invalid/action]" do
|
25
|
-
post :other_create, {song: {title: ""}}
|
26
|
-
assert_response 200
|
27
|
-
assert_equal @response.body, "OTHER SONG\n{:title=>["can't be blank"]}\n"
|
28
|
-
assert_template "songs/another_view"
|
29
|
-
end
|
30
|
-
|
31
|
-
test "Delete [html/valid]" do
|
32
|
-
song = Song::Create[song: {title: "You're Going Down"}].model
|
33
|
-
delete :destroy, id: song.id
|
34
|
-
assert_redirected_to songs_path
|
35
|
-
# assert that model is deleted.
|
36
|
-
end
|
37
|
-
|
38
|
-
test "respond with block [html/valid]" do
|
39
|
-
post :create_with_block, {song: {title: "You're Going Down"}}
|
40
|
-
assert_response 200
|
41
|
-
assert_equal "block run, valid: true", response.body
|
42
|
-
end
|
43
|
-
|
44
|
-
test "respond with block [html/invalid]" do
|
45
|
-
post :create_with_block, {song: {title: ""}}
|
46
|
-
assert_response 200
|
47
|
-
assert_equal "block run, valid: false", response.body
|
48
|
-
end
|
49
|
-
|
50
|
-
# JSON
|
51
|
-
test "Delete [json/valid]" do
|
52
|
-
song = Song::Create[song: {title: "You're Going Down"}].model
|
53
|
-
delete :destroy, id: song.id, format: :json
|
54
|
-
assert_response 204 # no content.
|
55
|
-
end
|
56
|
-
|
57
|
-
# JS
|
58
|
-
test "Delete [js/valid]" do
|
59
|
-
song = Song::Create[song: {title: "You're Going Down"}].model
|
60
|
-
assert_raises ActionView::MissingTemplate do
|
61
|
-
# js wants to render destroy.js.erb
|
62
|
-
delete :destroy, id: song.id, format: :js
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
test "Delete with formats [js/valid]" do
|
67
|
-
song = Song::Create[song: {title: "You're Going Down"}].model
|
68
|
-
|
69
|
-
delete :destroy_with_formats, id: song.id, format: :js
|
70
|
-
assert_response 200
|
71
|
-
assert_equal "Song slayer!", response.body
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class ResponderRespondWithJSONTest < ActionController::TestCase
|
76
|
-
tests BandsController
|
77
|
-
|
78
|
-
# JSON
|
79
|
-
test "Create [JSON/valid]" do
|
80
|
-
post :create, {name: "SNFU"}.to_json, format: :json
|
81
|
-
assert_response 201
|
82
|
-
assert_equal "SNFU", Band.last.name
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# TODO: merge with above tests on SongsController.
|
87
|
-
class ControllerRespondTest < ActionController::TestCase
|
88
|
-
tests BandsController
|
89
|
-
|
90
|
-
test "#respond with builds" do
|
91
|
-
post :create, band: {name: "SNFU"}, admin: true
|
92
|
-
assert_response 302
|
93
|
-
assert_equal "SNFU [ADMIN]", Band.last.name
|
94
|
-
end
|
95
|
-
end
|
data/test/rails/test_helper.rb
DELETED
data/test/responder_test.rb
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'trailblazer/operation/responder'
|
3
|
-
|
4
|
-
class Song
|
5
|
-
extend ActiveModel::Naming
|
6
|
-
|
7
|
-
class Operation < Trailblazer::Operation
|
8
|
-
include Model
|
9
|
-
model Song
|
10
|
-
include Responder
|
11
|
-
|
12
|
-
def process(params)
|
13
|
-
invalid! if params == false
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
module MyApp
|
19
|
-
class Song
|
20
|
-
extend ActiveModel::Naming
|
21
|
-
|
22
|
-
class Operation < Trailblazer::Operation
|
23
|
-
include Model
|
24
|
-
include Responder
|
25
|
-
model Song
|
26
|
-
|
27
|
-
def process(params)
|
28
|
-
invalid! if params == false
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class ResponderTestForModelWithoutNamespace < MiniTest::Spec
|
35
|
-
|
36
|
-
# test ::model_name
|
37
|
-
it { Song::Operation.model_name.name.must_equal "Song" }
|
38
|
-
it { Song::Operation.model_name.singular.must_equal "song" }
|
39
|
-
it { Song::Operation.model_name.plural.must_equal "songs" }
|
40
|
-
it { Song::Operation.model_name.element.must_equal "song" }
|
41
|
-
it { Song::Operation.model_name.human.must_equal "Song" }
|
42
|
-
it { Song::Operation.model_name.collection.must_equal "songs" }
|
43
|
-
it { Song::Operation.model_name.param_key.must_equal "song" }
|
44
|
-
it { Song::Operation.model_name.i18n_key.must_equal :"song" }
|
45
|
-
it { Song::Operation.model_name.route_key.must_equal "songs" }
|
46
|
-
it { Song::Operation.model_name.singular_route_key.must_equal "song" }
|
47
|
-
|
48
|
-
# #errors
|
49
|
-
it { Song::Operation.(true).errors.must_equal [] }
|
50
|
-
it { Song::Operation.(false).errors.must_equal [1] } # TODO: since we don't want responder to render anything, just return _one_ error. :)
|
51
|
-
|
52
|
-
# TODO: integration test with Controller.
|
53
|
-
end
|
54
|
-
|
55
|
-
|
56
|
-
class ResponderTestForModelWitNamespace < MiniTest::Spec
|
57
|
-
|
58
|
-
# test ::model_name
|
59
|
-
it { MyApp::Song::Operation.model_name.name.must_equal "MyApp::Song" }
|
60
|
-
it { MyApp::Song::Operation.model_name.singular.must_equal "my_app_song" }
|
61
|
-
it { MyApp::Song::Operation.model_name.plural.must_equal "my_app_songs" }
|
62
|
-
it { MyApp::Song::Operation.model_name.element.must_equal "song" }
|
63
|
-
it { MyApp::Song::Operation.model_name.human.must_equal "Song" }
|
64
|
-
it { MyApp::Song::Operation.model_name.collection.must_equal "my_app/songs" }
|
65
|
-
it { MyApp::Song::Operation.model_name.param_key.must_equal "my_app_song" } # "song" for AR.
|
66
|
-
it { MyApp::Song::Operation.model_name.i18n_key.must_equal :"my_app/song" }
|
67
|
-
it { MyApp::Song::Operation.model_name.route_key.must_equal "my_app_songs" } # "songs" for AR.
|
68
|
-
it { MyApp::Song::Operation.model_name.singular_route_key.must_equal "my_app_song" } # "song" for AR.
|
69
|
-
|
70
|
-
# #errors
|
71
|
-
it { MyApp::Song::Operation.(true).errors.must_equal [] }
|
72
|
-
it { MyApp::Song::Operation.(false).errors.must_equal [1] } # TODO: since we don't want responder to render anything, just return _one_ error. :)
|
73
|
-
|
74
|
-
# TODO: integration test with Controller.
|
75
|
-
end
|
data/test/uploaded_file_test.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'trailblazer/operation/uploaded_file'
|
3
|
-
|
4
|
-
class TempfileTest < MiniTest::Spec
|
5
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
class UploadedFileTest < MiniTest::Spec
|
9
|
-
let (:image) { File.open("test/fixtures/apotomo.png") }
|
10
|
-
let (:tempfile) { tmp = Tempfile.new("bla")
|
11
|
-
tmp.write image.read
|
12
|
-
tmp
|
13
|
-
}
|
14
|
-
|
15
|
-
let (:upload) { ActionDispatch::Http::UploadedFile.new(
|
16
|
-
tempfile: tempfile,
|
17
|
-
filename: "apotomo.png",
|
18
|
-
type: "image/png")
|
19
|
-
}
|
20
|
-
|
21
|
-
describe "#to_hash" do
|
22
|
-
before {
|
23
|
-
@uploaded_path = upload.tempfile.path
|
24
|
-
@subject = Trailblazer::Operation::UploadedFile.new(upload).to_hash
|
25
|
-
}
|
26
|
-
|
27
|
-
it { @subject[:filename].must_equal "apotomo.png" }
|
28
|
-
it { @subject[:type].must_equal "image/png" }
|
29
|
-
it { @subject[:tempfile_path].must_match /\w+_trailblazer_upload$/ }
|
30
|
-
|
31
|
-
|
32
|
-
# Rails upload file must be removed.
|
33
|
-
it {
|
34
|
-
File.exists?(@uploaded_path).must_equal false }
|
35
|
-
|
36
|
-
it { File.exists?(@subject[:tempfile_path]).must_equal true }
|
37
|
-
it { File.size(@subject[:tempfile_path]).must_equal image.size }
|
38
|
-
end
|
39
|
-
|
40
|
-
describe "::from_hash" do
|
41
|
-
let (:data) { Trailblazer::Operation::UploadedFile.new(upload).to_hash }
|
42
|
-
subject { Trailblazer::Operation::UploadedFile.from_hash(data) }
|
43
|
-
|
44
|
-
|
45
|
-
it { subject.original_filename.must_equal "apotomo.png" }
|
46
|
-
it { subject.content_type.must_equal "image/png" }
|
47
|
-
it { subject.tempfile.must_be_kind_of File }
|
48
|
-
it { subject.size.must_equal image.size }
|
49
|
-
|
50
|
-
# params is not modified.
|
51
|
-
it { params = data.clone and subject; data.must_equal params }
|
52
|
-
|
53
|
-
# Tempfile must have proper extension for further processing (sidekiq/imagemagick, etc).
|
54
|
-
it { subject.tempfile.path.must_match /\.png$/ }
|
55
|
-
|
56
|
-
# Tempfile must be unlinked after process is finished.
|
57
|
-
it do
|
58
|
-
@subject = Trailblazer::Operation::UploadedFile.from_hash(data)
|
59
|
-
|
60
|
-
processable_file = @subject.tempfile.path
|
61
|
-
File.exists?(processable_file).must_equal true # this file must be GCed since it's a Tempfile, that's the whole point.
|
62
|
-
# @subject = nil
|
63
|
-
# GC.start
|
64
|
-
# File.exists?(processable_file).must_equal false
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
|
69
|
-
describe "with custom tmp directory" do
|
70
|
-
describe "#to_hash" do
|
71
|
-
before {
|
72
|
-
@uploaded = Trailblazer::Operation::UploadedFile.new(upload, tmp_dir: tmp_dir)
|
73
|
-
@subject = @uploaded.to_hash[:tempfile_path]
|
74
|
-
}
|
75
|
-
|
76
|
-
it { @subject.must_match /\w+_trailblazer_upload$/ }
|
77
|
-
it { @subject.must_match /^\/tmp\/uploads\// }
|
78
|
-
|
79
|
-
it { File.exists?(@subject).must_equal true }
|
80
|
-
it { File.size(@subject).must_equal image.size }
|
81
|
-
|
82
|
-
it { @uploaded.instance_variable_get(:@with_tmp_dir).path.must_equal nil }
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
data/test/worker_test.rb
DELETED
@@ -1,124 +0,0 @@
|
|
1
|
-
# make sure #run always returns model
|
2
|
-
|
3
|
-
# in test with sidekiq/testing
|
4
|
-
# Operation.run #=> call perform_one and return [result, model] (model?)
|
5
|
-
|
6
|
-
require 'test_helper'
|
7
|
-
require 'trailblazer/operation'
|
8
|
-
require 'trailblazer/operation/worker'
|
9
|
-
require 'sidekiq/testing'
|
10
|
-
|
11
|
-
|
12
|
-
class WorkerTest < MiniTest::Spec
|
13
|
-
class Operation < Trailblazer::Operation
|
14
|
-
include Worker
|
15
|
-
|
16
|
-
def process(params)
|
17
|
-
with_symbol = params[:title]
|
18
|
-
with_string = params["title"]
|
19
|
-
@model = "I was working hard on #{params.inspect}. title:#{with_symbol} \"title\"=>#{with_string}"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class NoBackgroundOperation < Operation
|
24
|
-
def self.background?
|
25
|
-
false
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# test basic worker functionality.
|
30
|
-
describe "with sidekiq ss" do
|
31
|
-
it do
|
32
|
-
res = Operation.run(title: "Dragonfly")
|
33
|
-
|
34
|
-
res.kind_of?(String).must_equal true # for now, we return the job from sidekiq
|
35
|
-
Operation.jobs[0]["args"].must_equal([{"title"=>"Dragonfly"}])
|
36
|
-
Operation.perform_one.last.model.must_equal "I was working hard on {\"title\"=>\"Dragonfly\"}. title:Dragonfly \"title\"=>Dragonfly"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# without sidekiq, we don't have indifferent_access automatically.
|
41
|
-
it { NoBackgroundOperation.run(title: "Dragonfly").last.model.must_equal "I was working hard on {:title=>\"Dragonfly\"}. title:Dragonfly \"title\"=>" }
|
42
|
-
|
43
|
-
|
44
|
-
# test manual serialisation (to be done with UploadedFile etc automatically).
|
45
|
-
class SerializingOperation < Operation
|
46
|
-
include Worker
|
47
|
-
|
48
|
-
def self.serializable(params)
|
49
|
-
{wrap: params}
|
50
|
-
end
|
51
|
-
|
52
|
-
def deserializable(params)
|
53
|
-
params[:wrap]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe "with serialization in sidekiq" do
|
58
|
-
before { @res = SerializingOperation.run(title: "Dragonfly") }
|
59
|
-
|
60
|
-
it { @res.kind_of?(String).must_equal true } # for now, we return the job from sidekiq.
|
61
|
-
it { SerializingOperation.jobs[0]["args"].must_equal([{"wrap"=>{"title"=>"Dragonfly"}}]) }
|
62
|
-
it { SerializingOperation.perform_one.last.model.must_equal "I was working hard on {\"title\"=>\"Dragonfly\"}. title:Dragonfly \"title\"=>Dragonfly" }
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
require "trailblazer/operation/uploaded_file"
|
68
|
-
require "action_dispatch/http/upload"
|
69
|
-
class WorkerFileMarshallerTest < MiniTest::Spec
|
70
|
-
def uploaded_file(name)
|
71
|
-
tmp = Tempfile.new("bla")
|
72
|
-
tmp.write File.open("test/fixtures/#{name}").read
|
73
|
-
|
74
|
-
ActionDispatch::Http::UploadedFile.new(
|
75
|
-
tempfile: tmp,
|
76
|
-
filename: name,
|
77
|
-
type: "image/png")
|
78
|
-
end
|
79
|
-
|
80
|
-
class Operation < Trailblazer::Operation
|
81
|
-
contract do
|
82
|
-
property :title
|
83
|
-
property :image, file: true
|
84
|
-
|
85
|
-
property :album do
|
86
|
-
property :image, file: true
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
include Worker
|
91
|
-
include Worker::FileMarshaller # should be ContractFileMarshaller
|
92
|
-
|
93
|
-
def process(params)
|
94
|
-
@params = params
|
95
|
-
end
|
96
|
-
|
97
|
-
attr_reader :params
|
98
|
-
end
|
99
|
-
|
100
|
-
# TODO: no image
|
101
|
-
|
102
|
-
# with image serializes the file for later retrieval.
|
103
|
-
it do
|
104
|
-
Operation.run(title: "Dragonfly", image: uploaded_file("apotomo.png"), album: {image: uploaded_file("cells.png")})
|
105
|
-
|
106
|
-
args = Operation.jobs[0]["args"].first
|
107
|
-
args["title"].must_equal("Dragonfly")
|
108
|
-
args["image"]["filename"].must_equal "apotomo.png"
|
109
|
-
args["image"]["tempfile_path"].must_match /trailblazer_upload/
|
110
|
-
|
111
|
-
args["album"]["image"]["filename"].must_equal "cells.png"
|
112
|
-
|
113
|
-
_, op = Operation.perform_one # deserialize.
|
114
|
-
|
115
|
-
params = op.params
|
116
|
-
|
117
|
-
params["title"].must_equal("Dragonfly")
|
118
|
-
params[:title].must_equal("Dragonfly") # must allow indifferent_access.
|
119
|
-
params["image"].must_be_kind_of ActionDispatch::Http::UploadedFile
|
120
|
-
params["image"].original_filename.must_equal "apotomo.png"
|
121
|
-
params["album"]["image"].must_be_kind_of ActionDispatch::Http::UploadedFile
|
122
|
-
params["album"]["image"].original_filename.must_equal "cells.png"
|
123
|
-
end
|
124
|
-
end
|