require "teaspoon/environment" require "teaspoon/suite" require "teaspoon/instrumentation" module Teaspoon class Engine < ::Rails::Engine isolate_namespace Teaspoon routes do root to: "suite#index" match "/fixtures/*filename", to: "suite#fixtures", via: :get, as: "fixture" match "/:suite", to: "suite#show", via: :get, as: "suite", defaults: { suite: "default" } match "/:suite/:hook", to: "suite#hook", via: :post, defaults: { suite: "default", hook: "default" } end initializer :assets, group: :all do |app| begin Teaspoon::Environment.require_environment rescue Teaspoon::EnvironmentNotFound # it's ok for this to fail sometimes, like before the generator is run etc end Teaspoon::Engine.default_root_path(app.root) # default the root if it's not set Teaspoon::Engine.append_asset_paths(app.config.assets) # append the asset paths from the configuration Teaspoon::Engine.add_precompiled_assets(app.config.assets) end config.after_initialize do |app| Teaspoon::Engine.inject_instrumentation # inject our sprockets hack for instrumenting javascripts Teaspoon::Engine.prepend_routes(app) # prepend routes so a catchall doesn't get in the way end def self.default_root_path(root) Teaspoon.configuration.root ||= root end def self.append_asset_paths(assets) Teaspoon.configuration.asset_paths.each do |path| assets.paths << Teaspoon.configuration.root.join(path).to_s end # TODO: This breaks lazy loading of frameworks. Another way to avoid this? Teaspoon::Framework.available.keys.each do |framework| assets.paths += Teaspoon::Framework.fetch(framework).asset_paths end end def self.add_precompiled_assets(assets) assets.precompile += Teaspoon.configuration.asset_manifest end def self.inject_instrumentation Sprockets::Environment.send(:include, Teaspoon::SprocketsInstrumentation) Sprockets::CachedEnvironment.send(:include, Teaspoon::SprocketsInstrumentation) rescue NameError # Handle cached environment in Sprockets 2.x Sprockets::Index.send(:include, Teaspoon::SprocketsInstrumentation) end def self.prepend_routes(app) mount_at = Teaspoon.configuration.mount_at return if app.routes.recognize_path(mount_at)[:action] != "routing_error" rescue nil ActiveSupport.on_load(:action_controller) do require Teaspoon::Engine.root.join("app/controllers/teaspoon/suite_controller") end app.routes.prepend { mount Teaspoon::Engine => mount_at, as: "teaspoon" } end module ExceptionHandling def self.add_rails_handling return unless using_phantomjs? # debugging should be off to display errors in the suite_controller # Rails.application.config.assets.debug = false # we want rails to display exceptions Rails.application.config.action_dispatch.show_exceptions = true # override the render exception method in ActionDispatch to raise a javascript exception render_exceptions_with_javascript end private def self.using_phantomjs? Teaspoon::Driver.matches?(Teaspoon.configuration.driver, :phantomjs) end def self.render_exceptions_with_javascript ActionDispatch::DebugExceptions.class_eval do def render_exception(_env, exception) message = "#{exception.class.name}: #{exception.message}" body = "" [200, { "Content-Type" => "text/html;", "Content-Length" => body.bytesize.to_s }, [body]] end end end end end end class Sprockets::Rails::HelperAssetResolvers::Environment def raise_unless_precompiled_asset(path) if Rails.env.test? or Rails.env.development? # nothing, thank you else super end end end # Some Sprockets patches to work with Sprockets 2.x unless Sprockets::Asset.public_method_defined?(:filename) module Sprockets class Asset def filename pathname.to_s end end end end