trailblazer 1.0.0.rc2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|