describe "Rails development-mode support", :type => :rails do uses_rails_with_template :development_mode_system_spec, :rails_env => :development it "should automatically reload widgets if they change on disk" do expect_match("reload_widget", /before_reload/) # The sleep is unfortunate, but required: without it, Rails will not necessarily pick up our change, # especially if we run multiple tests back-to-back. (There's a maximum frequency at which Rails can # detect distinct file changes on disk, which on the order of 1 Hz -- i.e., once a second; any more # than this and it fails. This is irrelevant for human-centered development, but important for # tests like this.) sleep 1 splat_new_widget! expect_match("reload_widget", /after_reload/) end it "should automatically reload widgets if related files change on disk, even if they're named '.html.rb' at the end" do expect_match("reload_widget_with_html_extension", /with_html_extension.*helper: yo/) sleep 1 splat_new_module_for_reload_widget_failing! expect_exception("reload_widget_with_html_extension", NameError, "some_helper") sleep 1 splat_new_module_for_reload_widget! expect_match("reload_widget_with_html_extension", /with_html_extension.*helper: yo/) end it "should not autoload classes that live under views/ but don't start with a Views:: prefix" do expect_exception('the_class_should_not_load', 'NameError', /uninitialized constant DevelopmentModeSystemSpec::ClassShouldNotLoad/i) end it "should let you change the controller, and that should work fine, too" do expect(rails_server.get("replaced/reload_widget")).to match(/datum\s+one\s+datum/) sleep 1 splat_new_controller! expect(rails_server.get("replaced/reload_widget")).to match(/datum\s+two\s+datum/) end it "should, by default, format output" do expect_match("sample_output", %r{

hello, Jessica

}mi) end it "should, by default, output BEGIN/END debugging tags" do expect_match("sample_output", %r{ .* }mi) end it "should pick up changes to mailer views" do expect_match("mailer_view_test", /mail sent/i) mail = mail_sent_to('mailer_view_test@example.com') expect(mail[:body].strip).to match(%r{

this is the basic mail!

}mi) clear_mails! sleep 1 splat_new_mailer_view! expect_match("mailer_view_test", /mail sent/i) mail = mail_sent_to('mailer_view_test@example.com') expect(mail[:body].strip).to match(%r{

this is the NEW basic mail!

}mi) end it "should pick up changes to mailer layouts" do expect_match("mailer_layout_test", /mail sent/i) mail = mail_sent_to('mailer_layout_test@example.com') expect(mail[:body].strip).to match(%r{this is the layout, before.*this is the basic mail!.*this is the layout, after}mi) clear_mails! sleep 1 splat_new_mailer_layout! expect_match("mailer_layout_test", /mail sent/i) mail = mail_sent_to('mailer_layout_test@example.com') expect(mail[:body].strip).to match(%r{this is the NEW layout, before.*this is the basic mail!.*this is the NEW layout, after}mi) end it "should format output and output BEGIN/END debugging tags in mailers" do expect_match("mailer_formatting_test", /mail sent/i) mail = mail_sent_to('mailer_formatting_test@example.com') expect(mail[:body].strip).to eq(%{

this is the text!

}) end it "should allow referencing a widget by partial namespace" do expect_match("namespace_reference", /before.*referenced.*after/mi) end it "should allow you to toggle back and forth between two forms of referencing a superclass" do current_form = :full_reference 5.times do if current_form == :full_reference splat_full_reference_edit! else splat_partial_reference_edit! end sleep 1 $stderr.puts "checking for #{current_form.inspect}" expect_match("edit", /#{Regexp.escape(current_form.to_s)}/i) current_form = if current_form == :full_reference :partial_reference else :full_reference end end end private def splat_full_reference_edit! widget_file = File.join(rails_server.rails_root, "app/views/development_mode_system_spec/edit.rb") File.open(widget_file, 'w') do |f| f.puts <<-EOS module Views module DevelopmentModeSystemSpec if const_defined?(:Edit) $stderr.puts "(full) Edit constant: \#{const_get(:Edit).inspect}" $stderr.puts "(full) Edit superclass: \#{const_get(:Edit).superclass}/\#{const_get(:Edit).superclass.object_id}" if (::Views.const_defined?(:Base)) $stderr.puts "(full) Views::Base already defined: \#{::Views::Base.object_id}" else $stderr.puts "(full) Views::Base not defined" end $stderr.puts "(full) ::Views::Base: \#{::Views::Base.name}/\#{::Views::Base.object_id}" $stderr.puts "(full) Views::Base: \#{Views::Base.name}/\#{Views::Base.object_id}" else $stderr.puts "(full) No edit constant!" end class Edit < Views::Base def content widget(Views::DevelopmentModeSystemSpec::Form, :label => "full_reference") end end $stderr.puts "(full) After definition: \#{::Views::Base.object_id}" end end EOS end end def splat_partial_reference_edit! widget_file = File.join(rails_server.rails_root, "app/views/development_mode_system_spec/edit.rb") File.open(widget_file, 'w') do |f| f.puts <<-EOS module Views module DevelopmentModeSystemSpec if const_defined?(:Edit) $stderr.puts "(partial) Edit constant: \#{const_get(:Edit).inspect}" $stderr.puts "(partial) Edit superclass: \#{const_get(:Edit).superclass}/\#{const_get(:Edit).superclass.object_id}" if (::Views.const_defined?(:Base)) $stderr.puts "(partial) Views::Base already defined: \#{::Views::Base.object_id}" else $stderr.puts "(partial) Views::Base not defined" end $stderr.puts "(partial) ::Views::Base: \#{::Views::Base.name}/\#{::Views::Base.object_id}" $stderr.puts "(partial) Views::Base: \#{Views::Base.name}/\#{Views::Base.object_id}" else $stderr.puts "(partial) No edit constant!" end class Edit < Views::Base def content widget(Form, :label => "partial_reference") end end $stderr.puts "(partial) After definition: \#{::Views::Base.object_id}" end end EOS end end def splat_new_widget! reload_file = File.join(rails_server.rails_root, 'app/views/development_mode_system_spec/reload_widget.rb') File.open(reload_file, 'w') do |f| f.puts <<-EOS class Views::DevelopmentModeSystemSpec::ReloadWidget < Fortitude::Widgets::Html5 needs :datum def content p "after_reload: datum \#{datum} datum" end end EOS end end def splat_new_module_for_reload_widget_failing! module_file = File.join(rails_server.rails_root, 'app/views/shared/some_module.rb') File.open(module_file, 'w') do |f| f.puts <<-EOS module Views::Shared::SomeModule end EOS end end def splat_new_module_for_reload_widget! module_file = File.join(rails_server.rails_root, 'app/views/shared/some_module.rb') File.open(module_file, 'w') do |f| f.puts <<-EOS module Views::Shared::SomeModule def some_helper "yo" end end EOS end end def splat_new_controller! controller_file = File.join(rails_server.rails_root, 'app/controllers/replaced_controller.rb') File.open(controller_file, 'w') do |f| f.puts <<-EOS class ReplacedController < ApplicationController def reload_widget @datum = "two" end end EOS end end def splat_new_mailer_view! reload_file = File.join(rails_server.rails_root, 'app/views/development_mode_mailer/mailer_view_test.rb') File.open(reload_file, 'w') do |f| f.puts <<-EOS class Views::DevelopmentModeMailer::MailerViewTest < Fortitude::Widgets::Html5 def content p "this is the NEW basic mail!" end end EOS end end def splat_new_mailer_layout! reload_file = File.join(rails_server.rails_root, 'app/views/layouts/mail_layout.rb') File.open(reload_file, 'w') do |f| f.puts <<-EOS class Views::Layouts::MailLayout < Fortitude::Widgets::Html5 def content p "this is the NEW layout, before" yield p "this is the NEW layout, after" end end EOS end end end