describe "Rails generator support", :type => :rails do # We use development mode so that we don't have to bounce the Rails server every time we # generate something new. uses_rails_with_template :generators_system_spec, :rails_env => :development def views_base_path @views_base_path ||= File.join(rails_server.rails_root, 'app', 'views', 'base.rb') end def clean_views_base! File.delete(views_base_path) if File.exist?(views_base_path) end def ensure_views_base_is_correct! expect(File.exist?(views_base_path)).to be_truthy contents = File.read(views_base_path) expect(contents).to match(/Views::Base\s*<\s*Fortitude::Widget\s*\n/) expect(contents).to match(/doctype\s+:html5/) end def generate!(what) rails_server.run_command_in_rails_root!("rails generate #{what}") end def ensure_file_matches!(subpath, regexp) path = File.join(rails_server.rails_root, subpath) expect(File.exist?(path)).to be_truthy contents = File.read(path) expect(contents).to match(regexp) end def ensure_action_matches!(subpath, regexp) response = rails_server.get(subpath) expect(response).to match(regexp) response end describe "base view generation" do it "should be able to generate a Views::Base file" do clean_views_base! generate!("fortitude:base_view") ensure_views_base_is_correct! end end describe "controller generation" do it "should be able to generate a controller action that creates a Fortitude view" do generate!("controller gen_con1 act_ion1") ensure_file_matches!('app/views/gen_con1/act_ion1.html.rb', /Views::GenCon1::ActIon1\s*<\s*Views::Base/) ensure_action_matches!('gen_con1/act_ion1', %r{

\s*GenCon1#act_ion1\s*

\s*

\s*Find me in app/views/gen_con1/act_ion1.html.rb\s*

}mi) end it "should generate a Views::Base file" do clean_views_base! generate!("controller gencon2 action2") ensure_views_base_is_correct! end it "should not overwrite an existing Views::Base file" do prior_contents = "class Views::Base < Fortitude::Widget\n doctype :html5\n def something\n end\nend" File.open(views_base_path, 'w') { |f| f.puts prior_contents } generate!("controller gencon3 action3") expect(File.exist?(views_base_path)).to be_truthy expect(File.read(views_base_path).strip).to eq(prior_contents.strip) end it "should allow switching back to ERb if desired" do generate!("controller gen_con4 act_ion1 -e erb") expect(File.exist?(File.join(rails_server.rails_root, 'app/views/gen_con4/act_ion1.html.rb'))).to be_falsey expect(File.exist?(File.join(rails_server.rails_root, 'app/views/gen_con4/act_ion1.html.erb'))).to be_truthy end end describe "mailer generation" do def mailer_path_suffix if rails_server.actual_rails_version =~ /^[34]\./ "" else "_mailer" end end def mailer_class_suffix if rails_server.actual_rails_version =~ /^[34]\./ "" else "Mailer" end end it "should be able to generate a mailer that creates a Fortitude view and layout" do generate!("mailer gen1 act_ion1") ensure_file_matches!("app/views/gen1#{mailer_path_suffix}/act_ion1.html.rb", /Views::Gen1#{mailer_class_suffix}::ActIon1\s*<\s*Views::Base/) end it "should generate a Views::Base file" do clean_views_base! generate!("mailer gen1 act_ion1") ensure_views_base_is_correct! end it "should not overwrite an existing Views::Base file" do prior_contents = "class Views::Base < Fortitude::Widget\n doctype :html5\n def something\n end\nend" File.open(views_base_path, 'w') { |f| f.puts prior_contents } generate!("mailer gen1 act_ion1") expect(File.exist?(views_base_path)).to be_truthy expect(File.read(views_base_path).strip).to eq(prior_contents.strip) end end describe "scaffold generation" do it "should be able to generate a scaffold" do generate!("scaffold MyModel foo:string bar:integer") # We need to disable CSRF protection, since we're not using a session application_controller = File.join(rails_server.rails_root, 'app', 'controllers', 'application_controller.rb') application_controller_contents = File.read(application_controller) if (! application_controller_contents.gsub!(/^\s*protect_from_forgery.*$/, "protect_from_forgery :with => :null_session")) application_controller_contents.gsub!(/^end\Z/, " protect_from_forgery :with => :null_session\nend\n") end File.open(application_controller, 'w') { |f| f.puts application_controller_contents } # Need this to create the table (which will be in SQLite by default, which is easy), or else # the controller actions will fail since there will be no such table. rails_server.run_command_in_rails_root!("rake db:migrate") ensure_file_matches!('app/views/my_models/index.html.rb', %r{class Views::MyModels::Index < Views::Base}) ensure_file_matches!('app/views/my_models/show.html.rb', %r{class Views::MyModels::Show < Views::Base}) ensure_file_matches!('app/views/my_models/edit.html.rb', %r{class Views::MyModels::Edit < Views::Base}) ensure_file_matches!('app/views/my_models/new.html.rb', %r{class Views::MyModels::New < Views::Base}) ensure_file_matches!('app/views/my_models/form.html.rb', %r{class Views::MyModels::Form < Views::Base}) # Ruby 1.8.7 and Rails 3.0.x seems to have issues unless we do this, sadly... rails_server.stop! rails_server.start! # This won't check that the views all have the right HTML in them (that's nearly impossible without # just duplicating exactly what they're supposed to contain, right here), but it will check that they # compile and produce some kind of HTML output. ensure_action_matches!('my_models', %r{

\s*My Models\s*

}m) new_html = ensure_action_matches!('my_models/new', %r{ { 'my_model[foo]' => 'foo1', 'my_model[bar]' => 23456, :commit => 'Create My model' }, :ignore_status_code => true) new_url = if (300..399).include?(Integer(response.code)) response['Location'] else raise "Response didn't seem to give us a redirect: #{response.code.inspect} (from #{response.inspect})" end path = URI.parse(new_url).path ensure_action_matches!(path, %r{foo1.*23456}m) ensure_action_matches!("#{path}/edit", %r{Editing.*foo1.*23456}m) ensure_action_matches!("my_models", %r{

\s*My Models\s*

.*foo1.*23456}m) end end end