autoforme 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/mtm_spec.rb ADDED
@@ -0,0 +1,333 @@
1
+ require './spec/spec_helper'
2
+
3
+ describe AutoForme do
4
+ before(:all) do
5
+ db_setup(:artists=>[[:name, :string]], :albums=>[[:name, :string]], :albums_artists=>[[:album_id, :integer, {:table=>:albums}], [:artist_id, :integer, {:table=>:artists}]])
6
+ model_setup(:Artist=>[:artists, [[:many_to_many, :albums]]], :Album=>[:albums, [[:many_to_many, :artists]]])
7
+ end
8
+ after(:all) do
9
+ Object.send(:remove_const, :Album)
10
+ Object.send(:remove_const, :Artist)
11
+ end
12
+
13
+ it "should have basic many to many association editing working" do
14
+ app_setup do
15
+ model Artist do
16
+ mtm_associations :albums
17
+ end
18
+ model Album
19
+ end
20
+
21
+ Artist.create(:name=>'Artist1')
22
+ Album.create(:name=>'Album1')
23
+ Album.create(:name=>'Album2')
24
+ Album.create(:name=>'Album3')
25
+
26
+ visit("/Artist/mtm_edit")
27
+ page.find('title').text.should == 'Artist - Many To Many Edit'
28
+ select("Artist1")
29
+ click_button "Edit"
30
+
31
+ select("albums")
32
+ click_button "Edit"
33
+
34
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album1", "Album2", "Album3"]
35
+ all('select')[1].all('option').map{|s| s.text}.should == []
36
+ select("Album1", :from=>"Associate With")
37
+ click_button "Update"
38
+ page.html.should =~ /Updated albums association for Artist/
39
+ Artist.first.albums.map{|x| x.name}.should == %w'Album1'
40
+
41
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album2", "Album3"]
42
+ all('select')[1].all('option').map{|s| s.text}.should == ["Album1"]
43
+ select("Album2", :from=>"Associate With")
44
+ select("Album3", :from=>"Associate With")
45
+ select("Album1", :from=>"Disassociate From")
46
+ click_button "Update"
47
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2 Album3'
48
+
49
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album1"]
50
+ all('select')[1].all('option').map{|s| s.text}.should == ["Album2", "Album3"]
51
+ end
52
+
53
+ it "should have many to many association editing working with autocompletion" do
54
+ app_setup do
55
+ model Artist do
56
+ mtm_associations :albums
57
+ end
58
+ model Album do
59
+ autocomplete_options({})
60
+ end
61
+ end
62
+
63
+ Artist.create(:name=>'Artist1')
64
+ a1 = Album.create(:name=>'Album1')
65
+ a2 = Album.create(:name=>'Album2')
66
+ a3 = Album.create(:name=>'Album3')
67
+
68
+ visit("/Artist/mtm_edit")
69
+ select("Artist1")
70
+ click_button "Edit"
71
+
72
+ select("albums")
73
+ click_button "Edit"
74
+
75
+ all('select')[0].all('option').map{|s| s.text}.should == []
76
+ fill_in "Associate With", :with=>a1.id
77
+ click_button "Update"
78
+ page.html.should =~ /Updated albums association for Artist/
79
+ Artist.first.albums.map{|x| x.name}.should == %w'Album1'
80
+
81
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album1"]
82
+ fill_in "Associate With", :with=>a2.id
83
+ select("Album1", :from=>"Disassociate From")
84
+ click_button "Update"
85
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2'
86
+
87
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album2"]
88
+ select("Album2", :from=>"Disassociate From")
89
+ click_button "Update"
90
+ Artist.first.refresh.albums.map{|x| x.name}.should == []
91
+ all('select')[0].all('option').map{|s| s.text}.should == []
92
+ end
93
+
94
+ it "should have inline many to many association editing working" do
95
+ app_setup do
96
+ model Artist do
97
+ inline_mtm_associations :albums
98
+ end
99
+ model Album
100
+ end
101
+
102
+ Artist.create(:name=>'Artist1')
103
+ Album.create(:name=>'Album1')
104
+ Album.create(:name=>'Album2')
105
+ Album.create(:name=>'Album3')
106
+
107
+ visit("/Artist/edit")
108
+ select("Artist1")
109
+ click_button "Edit"
110
+ select 'Album1'
111
+ click_button 'Add'
112
+ page.html.should =~ /Updated albums association for Artist/
113
+ Artist.first.albums.map{|x| x.name}.should == %w'Album1'
114
+
115
+ select 'Album2'
116
+ click_button 'Add'
117
+ Artist.first.refresh.albums.map{|x| x.name}.sort.should == %w'Album1 Album2'
118
+
119
+ click_button 'Remove'
120
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2'
121
+
122
+ select 'Album3'
123
+ click_button 'Add'
124
+ Artist.first.refresh.albums.map{|x| x.name}.sort.should == %w'Album2 Album3'
125
+ end
126
+
127
+ it "should have inline many to many association editing working with autocompletion" do
128
+ app_setup do
129
+ model Artist do
130
+ inline_mtm_associations :albums
131
+ end
132
+ model Album do
133
+ autocomplete_options({})
134
+ end
135
+ end
136
+
137
+ Artist.create(:name=>'Artist1')
138
+ a1 = Album.create(:name=>'Album1')
139
+ a2 = Album.create(:name=>'Album2')
140
+ a3 = Album.create(:name=>'Album3')
141
+
142
+ visit("/Artist/edit")
143
+ select("Artist1")
144
+ click_button "Edit"
145
+ fill_in 'Albums', :with=>a1.id.to_s
146
+ click_button 'Add'
147
+ page.html.should =~ /Updated albums association for Artist/
148
+ Artist.first.albums.map{|x| x.name}.should == %w'Album1'
149
+
150
+ fill_in 'Albums', :with=>a2.id.to_s
151
+ click_button 'Add'
152
+ Artist.first.refresh.albums.map{|x| x.name}.sort.should == %w'Album1 Album2'
153
+
154
+ click_button 'Remove'
155
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2'
156
+
157
+ fill_in 'Albums', :with=>a3.id.to_s
158
+ click_button 'Add'
159
+ Artist.first.refresh.albums.map{|x| x.name}.sort.should == %w'Album2 Album3'
160
+ end
161
+
162
+ it "should have working many to many association links on show and edit pages" do
163
+ app_setup do
164
+ model Artist do
165
+ mtm_associations :albums
166
+ association_links :all_except_mtm
167
+ end
168
+ model Album do
169
+ mtm_associations [:artists]
170
+ association_links :all
171
+ end
172
+ end
173
+
174
+ visit("/Artist/new")
175
+ fill_in 'Name', :with=>'Artist1'
176
+ click_button 'Create'
177
+ click_link 'Edit'
178
+ select 'Artist1'
179
+ click_button 'Edit'
180
+ page.html.should_not =~ /Albums/
181
+
182
+ visit("/Album/new")
183
+ fill_in 'Name', :with=>'Album1'
184
+ click_button 'Create'
185
+ click_link 'Edit'
186
+ select 'Album1'
187
+ click_button 'Edit'
188
+ click_link 'associate'
189
+ select("Artist1", :from=>"Associate With")
190
+ click_button 'Update'
191
+ click_link 'Show'
192
+ select 'Album1'
193
+ click_button 'Show'
194
+ click_link 'Artist1'
195
+ page.current_path.should =~ %r{Artist/show/\d+}
196
+ page.html.should_not =~ /Albums/
197
+ end
198
+
199
+ it "should have many to many association editing working when associated class is not using autoforme" do
200
+ app_setup do
201
+ model Artist do
202
+ mtm_associations [:albums]
203
+ end
204
+ end
205
+
206
+ Artist.create(:name=>'Artist1')
207
+ Album.create(:name=>'Album1')
208
+ Album.create(:name=>'Album2')
209
+ Album.create(:name=>'Album3')
210
+
211
+ visit("/Artist/mtm_edit")
212
+ select("Artist1")
213
+ click_button "Edit"
214
+
215
+ select("albums")
216
+ click_button "Edit"
217
+
218
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album1", "Album2", "Album3"]
219
+ all('select')[1].all('option').map{|s| s.text}.should == []
220
+ select("Album1", :from=>"Associate With")
221
+ click_button "Update"
222
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album1'
223
+
224
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album2", "Album3"]
225
+ all('select')[1].all('option').map{|s| s.text}.should == ["Album1"]
226
+ select("Album2", :from=>"Associate With")
227
+ select("Album3", :from=>"Associate With")
228
+ select("Album1", :from=>"Disassociate From")
229
+ click_button "Update"
230
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2 Album3'
231
+
232
+ all('select')[0].all('option').map{|s| s.text}.should == ["Album1"]
233
+ all('select')[1].all('option').map{|s| s.text}.should == ["Album2", "Album3"]
234
+ end
235
+
236
+ it "should use filter/order from associated class" do
237
+ app_setup do
238
+ model Artist do
239
+ mtm_associations :all
240
+ end
241
+ model Album do
242
+ filter{|ds, req| ds.where(:name=>'A'..'M')}
243
+ order :name
244
+ end
245
+ end
246
+
247
+ Artist.create(:name=>'Artist1')
248
+ Album.create(:name=>'E1')
249
+ Album.create(:name=>'B1')
250
+ Album.create(:name=>'O1')
251
+
252
+ visit("/Artist/mtm_edit")
253
+ select("Artist1")
254
+ click_button "Edit"
255
+ select("albums")
256
+ click_button "Edit"
257
+
258
+ all('select')[0].all('option').map{|s| s.text}.should == ["B1", "E1"]
259
+ all('select')[1].all('option').map{|s| s.text}.should == []
260
+ select("E1", :from=>"Associate With")
261
+ click_button "Update"
262
+ Artist.first.albums.map{|x| x.name}.should == %w'E1'
263
+
264
+ all('select')[0].all('option').map{|s| s.text}.should == ["B1"]
265
+ all('select')[1].all('option').map{|s| s.text}.should == ["E1"]
266
+ select("B1", :from=>"Associate With")
267
+ select("E1", :from=>"Disassociate From")
268
+ click_button "Update"
269
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'B1'
270
+
271
+ all('select')[0].all('option').map{|s| s.text}.should == ["E1"]
272
+ all('select')[1].all('option').map{|s| s.text}.should == ["B1"]
273
+
274
+ select("B1", :from=>"Disassociate From")
275
+ Album.where(:name=>'B1').update(:name=>'Z1')
276
+ proc{click_button "Update"}.should raise_error(Sequel::NoMatchingRow)
277
+
278
+ visit('/Artist/mtm_edit')
279
+ select("Artist1")
280
+ click_button "Edit"
281
+ select("albums")
282
+ click_button "Edit"
283
+ select("E1", :from=>"Associate With")
284
+ Album.where(:name=>'E1').update(:name=>'Y1')
285
+ proc{click_button "Update"}.should raise_error(Sequel::NoMatchingRow)
286
+
287
+ visit('/Artist/mtm_edit')
288
+ select("Artist1")
289
+ click_button "Edit"
290
+ select("albums")
291
+ click_button "Edit"
292
+ all('select')[0].all('option').map{|s| s.text}.should == []
293
+ all('select')[1].all('option').map{|s| s.text}.should == []
294
+ end
295
+
296
+ it "should support column options on mtm_edit page" do
297
+ app_setup do
298
+ model Artist do
299
+ mtm_associations :albums
300
+ column_options :albums=>{:as=>:checkbox, :remove=>{:name_method=>proc{|obj| obj.name * 2}}}
301
+ end
302
+ model Album do
303
+ display_name{|obj, req| obj.name + "2"}
304
+ end
305
+ end
306
+
307
+ Artist.create(:name=>'Artist1')
308
+ Album.create(:name=>'Album1')
309
+ Album.create(:name=>'Album2')
310
+ Album.create(:name=>'Album3')
311
+
312
+ visit("/Artist/mtm_edit")
313
+ select("Artist1")
314
+ click_button "Edit"
315
+
316
+ select("albums")
317
+ click_button "Edit"
318
+
319
+ check "Album12"
320
+ click_button "Update"
321
+ Artist.first.albums.map{|x| x.name}.should == %w'Album1'
322
+
323
+ check "Album1Album1"
324
+ check "Album22"
325
+ check "Album32"
326
+ click_button "Update"
327
+ Artist.first.refresh.albums.map{|x| x.name}.should == %w'Album2 Album3'
328
+
329
+ check "Album12"
330
+ check "Album2Album2"
331
+ check "Album3Album3"
332
+ end
333
+ end
@@ -0,0 +1,75 @@
1
+ require 'rubygems'
2
+ require 'action_controller/railtie'
3
+ require 'autoforme'
4
+
5
+ RSpec.configure do |c|
6
+ c.after(:each) do |example|
7
+ if Object.const_defined?(:AutoformeController)
8
+ Object.send(:remove_const, :AutoformeController)
9
+ Rails.application = nil
10
+ end
11
+ end
12
+ end
13
+
14
+ class AutoFormeSpec::App
15
+ def self.autoforme(klass=nil, opts={}, &block)
16
+ sc = Class.new(Rails::Application)
17
+ framework = nil
18
+ sc.class_eval do
19
+ controller = Class.new(ActionController::Base)
20
+ Object.send(:const_set, :AutoformeController, controller)
21
+
22
+ resolver = Class.new(ActionView::Resolver)
23
+ resolver.class_eval do
24
+ template = ActionView::Template
25
+ t = [template.new(<<HTML, "layout", template.handler_for_extension(:erb), {:virtual_path=>'layout', :format=>'erb', :updated_at=>Time.now})]
26
+ <!DOCTYPE html>
27
+ <html>
28
+ <head><title><%= @autoforme_action.title if @autoforme_action %></title></head>
29
+ <body>
30
+ <% if flash[:notice] %>
31
+ <div class="alert alert-success"><p><%= flash[:notice] %></p></div>
32
+ <% end %>
33
+ <% if flash[:error] %>
34
+ <div class="alert alert-error"><p><%= flash[:error] %></p></div>
35
+ <% end %>
36
+ <%= yield %>
37
+ </body></html>"
38
+ HTML
39
+
40
+ define_method(:find_templates){|*args| t}
41
+ end
42
+
43
+ controller.class_eval do
44
+ self.view_paths = resolver.new
45
+ layout 'layout'
46
+
47
+ def session_set
48
+ session.merge!(params)
49
+ render :text=>''
50
+ end
51
+
52
+ AutoForme.for(:rails, self, opts) do
53
+ framework = self
54
+ model_type :sequel
55
+ if klass
56
+ model(klass, &block)
57
+ elsif block
58
+ instance_eval(&block)
59
+ end
60
+ end
61
+ end
62
+
63
+ config.secret_token = routes.append do
64
+ get 'session/set', :controller=>'autoforme', :action=>'session_set'
65
+ end.inspect
66
+ config.active_support.deprecation = :stderr
67
+ config.middleware.delete(ActionDispatch::ShowExceptions)
68
+ config.middleware.delete("Rack::Lock")
69
+ config.secret_key_base = 'foo'
70
+ config.eager_load = true
71
+ initialize!
72
+ end
73
+ [sc, framework]
74
+ end
75
+ end
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'sequel'
3
+ require 'logger'
4
+
5
+ RSpec.configure do |c|
6
+ c.around(:each) do |example|
7
+ if db
8
+ db.transaction(:rollback=>:always){example.run}
9
+ else
10
+ example.run
11
+ end
12
+ end
13
+ end
14
+
15
+ module AutoFormeSpec
16
+ TYPE_MAP = {:string=>String, :integer=>Integer}
17
+ def self.db_setup(tables)
18
+ db = Sequel.connect(ENV['DATABASE_URL'] || 'sqlite:/')
19
+ #db.loggers << Logger.new($stdout)
20
+ tables.each do |table, columns|
21
+ db.create_table(table) do
22
+ primary_key :id
23
+ columns.each do |name, type, opts|
24
+ column name, TYPE_MAP[type], opts||{}
25
+ end
26
+ end
27
+ end
28
+ db
29
+ end
30
+
31
+ def self.model_setup(db, models)
32
+ models.each do |name, (table, associations)|
33
+ klass = Class.new(Sequel::Model(db[table]))
34
+ Object.const_set(name, klass)
35
+ klass.class_eval do
36
+ if associations
37
+ associations.each do |type, assoc, opts|
38
+ associate(type, assoc, opts||{})
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'sinatra/base'
3
+ require 'autoforme'
4
+ require 'sinatra/flash'
5
+ require 'rack/csrf'
6
+
7
+ class AutoFormeSpec::App < Sinatra::Base
8
+ disable :run
9
+ enable :sessions
10
+ enable :raise_errors
11
+ set :environment, "test"
12
+ register Sinatra::Flash
13
+ use Rack::Csrf
14
+
15
+ get '/session/set' do
16
+ session.merge!(params)
17
+ ''
18
+ end
19
+
20
+ template :layout do
21
+ <<HTML
22
+ <!DOCTYPE html>
23
+ <html>
24
+ <head><title><%= @autoforme_action.title if @autoforme_action %></title></head>
25
+ <body>
26
+ <% if flash[:notice] %>
27
+ <div class="alert alert-success"><p><%= flash[:notice] %></p></div>
28
+ <% end %>
29
+ <% if flash[:error] %>
30
+ <div class="alert alert-error"><p><%= flash[:error] %></p></div>
31
+ <% end %>
32
+ <%= yield %>
33
+ </body></html>"
34
+ HTML
35
+ end
36
+
37
+ def self.autoforme(klass=nil, opts={}, &block)
38
+ sc = Class.new(self)
39
+ framework = nil
40
+ sc.class_eval do
41
+ AutoForme.for(:sinatra, self, opts) do
42
+ framework = self
43
+ model_type :sequel
44
+ if klass
45
+ model(klass, &block)
46
+ elsif block
47
+ instance_eval(&block)
48
+ end
49
+ end
50
+ end
51
+ [sc, framework]
52
+ end
53
+ end
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require 'capybara'
3
+ require 'capybara/dsl'
4
+ require 'capybara/rspec/matchers'
5
+ require 'rack/test'
6
+
7
+ module AutoFormeSpec
8
+ end
9
+
10
+ require './spec/sequel_spec_helper'
11
+
12
+ case ENV['FRAMEWORK']
13
+ when 'rails'
14
+ require './spec/rails_spec_helper'
15
+ else
16
+ require './spec/sinatra_spec_helper'
17
+ end
18
+
19
+ RSpec::Core::ExampleGroup.class_eval do
20
+ include Rack::Test::Methods
21
+ include Capybara::DSL
22
+ include Capybara::RSpecMatchers
23
+
24
+ attr_reader :app
25
+ attr_reader :db
26
+ attr_reader :framework
27
+ attr_reader :model
28
+
29
+ def app=(app)
30
+ @app = Capybara.app = app
31
+ end
32
+
33
+ def db_setup(tables, &block)
34
+ @db = AutoFormeSpec.db_setup(tables)
35
+ end
36
+
37
+ def model_setup(models)
38
+ AutoFormeSpec.model_setup(db, models)
39
+ end
40
+
41
+ def app_setup(klass=nil, opts={}, &block)
42
+ app, @framework = AutoFormeSpec::App.autoforme(klass, opts, &block)
43
+ self.app = app
44
+ @model = @framework.models[klass.name] if klass
45
+ end
46
+
47
+ after do
48
+ Capybara.reset_sessions!
49
+ Capybara.use_default_driver
50
+ end
51
+ end