test: add controller and filter tests
This commit is contained in:
1 parent
c079abed00
commit
95ad583c16
2 files changed
+202
No files matched your search
@@ -0,0 +1,116 @@
|
|||||||
|
require 'minitest/autorun'
|
||||||
|
require 'prism'
|
||||||
|
require 'support'
|
||||||
|
require 'tmpdir'
|
||||||
|
require 'fileutils'
|
||||||
|
|
||||||
|
class ControllerTest < Minitest::Test
|
||||||
|
include TestSupport
|
||||||
|
|
||||||
|
def setup
|
||||||
|
@views_dir = Dir.mktmpdir('prism-controller-views')
|
||||||
|
write_views
|
||||||
|
define_controller
|
||||||
|
define_app
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
FileUtils.remove_entry(@views_dir)
|
||||||
|
%i[PostsController PostsApp].each { |name| Object.send(:remove_const, name) if Object.const_defined?(name) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_views
|
||||||
|
FileUtils.mkdir_p(File.join(@views_dir, 'posts'))
|
||||||
|
FileUtils.mkdir_p(File.join(@views_dir, 'layouts'))
|
||||||
|
File.write(File.join(@views_dir, 'layouts', 'application.erb'), <<~ERB)
|
||||||
|
<!doctype html><html><body><%== content %></body></html>
|
||||||
|
ERB
|
||||||
|
File.write(File.join(@views_dir, 'posts', 'index.erb'), <<~ERB)
|
||||||
|
<ul><% posts.each do |title| %><%== partial('post', locals: { title: title }) %><% end %></ul>
|
||||||
|
ERB
|
||||||
|
File.write(File.join(@views_dir, 'posts', '_post.erb'), '<li><%= title %></li>')
|
||||||
|
File.write(File.join(@views_dir, 'posts', 'show.erb'), '<h1><%= id %></h1>')
|
||||||
|
end
|
||||||
|
|
||||||
|
def define_controller
|
||||||
|
views_dir = @views_dir
|
||||||
|
controller_class = Class.new(Prism::Controller) do
|
||||||
|
layout :application
|
||||||
|
views_root views_dir
|
||||||
|
|
||||||
|
before_action :set_common, only: %i[index show]
|
||||||
|
after_action :mark_served
|
||||||
|
|
||||||
|
def self.served_log
|
||||||
|
@served_log ||= []
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_common
|
||||||
|
@posts = ['first post', 'second post']
|
||||||
|
end
|
||||||
|
|
||||||
|
def index
|
||||||
|
render(:index, locals: { posts: @posts })
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render(:show, layout: nil, locals: { id: params['id'] })
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
halt(201, JSON.generate(created: params['title']))
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_served
|
||||||
|
self.class.served_log << action_name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Object.const_set(:PostsController, controller_class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def define_app
|
||||||
|
app_class = Class.new(Prism::Application) do
|
||||||
|
get '/posts', to: 'posts#index', as: :posts
|
||||||
|
get '/posts/:id', to: 'posts#show', as: :post
|
||||||
|
post '/posts', to: 'posts#create'
|
||||||
|
end
|
||||||
|
Object.const_set(:PostsApp, app_class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(method, path, **opts)
|
||||||
|
PostsApp.call(env_for(method, path, **opts))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_index_renders_with_layout_and_partials
|
||||||
|
_, _, body = call('GET', '/posts')
|
||||||
|
html = body.join
|
||||||
|
assert_includes html, '<!doctype html>'
|
||||||
|
assert_includes html, '<li>first post</li>'
|
||||||
|
assert_includes html, '<li>second post</li>'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_show_renders_action_template
|
||||||
|
_, _, body = call('GET', '/posts/42')
|
||||||
|
assert_equal '<h1>42</h1>', body.join
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_before_action_runs_with_only_filter
|
||||||
|
PostsController.served_log.clear
|
||||||
|
call('GET', '/posts')
|
||||||
|
call('GET', '/posts/1')
|
||||||
|
call('POST', '/posts')
|
||||||
|
assert_equal %w[index show create], PostsController.served_log
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_action_uses_halt
|
||||||
|
status, _, body = call('POST', '/posts', headers: { 'Content-Type' => 'application/x-www-form-urlencoded' }, body: 'title=hello')
|
||||||
|
assert_equal 201, status
|
||||||
|
assert_equal 'hello', JSON.parse(body.join)['created']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_named_route_url_for
|
||||||
|
status, _, body = call('GET', '/posts/9')
|
||||||
|
assert_equal 200, status
|
||||||
|
assert_equal PostsApp.router.path_to(:post, id: 9), '/posts/9'
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
require 'minitest/autorun'
|
||||||
|
require 'prism'
|
||||||
|
require 'support'
|
||||||
|
|
||||||
|
class FilterController < Prism::Controller
|
||||||
|
before_action(only: %i[index]) { @log = (@log || []) << 'inline-before' }
|
||||||
|
before_action :require_token, except: %i[public_action]
|
||||||
|
after_action :log_after, except: %i[public_action]
|
||||||
|
|
||||||
|
def self.after_log
|
||||||
|
@after_log ||= []
|
||||||
|
end
|
||||||
|
|
||||||
|
def index
|
||||||
|
json(log: @log)
|
||||||
|
end
|
||||||
|
|
||||||
|
def secret
|
||||||
|
json(reached: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def public_action
|
||||||
|
json(reached: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def require_token
|
||||||
|
halt(401, 'no token') unless params['token'] == 'ok'
|
||||||
|
end
|
||||||
|
|
||||||
|
def log_after
|
||||||
|
self.class.after_log << action_name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FilterApp < Prism::Application
|
||||||
|
get '/index', to: 'filter#index'
|
||||||
|
get '/secret', to: 'filter#secret'
|
||||||
|
get '/public', to: 'filter#public_action'
|
||||||
|
end
|
||||||
|
|
||||||
|
class ControllerFiltersTest < Minitest::Test
|
||||||
|
include TestSupport
|
||||||
|
|
||||||
|
def setup
|
||||||
|
FilterController.after_log.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(method, path, **opts)
|
||||||
|
FilterApp.call(env_for(method, path, **opts))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_inline_before_action_block_runs_and_scoped_to_only
|
||||||
|
_, _, body = call('GET', '/index?token=ok')
|
||||||
|
assert_equal ['inline-before'], JSON.parse(body.join)['log']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_before_action_with_except_still_guards_other_actions
|
||||||
|
status, _, body = call('GET', '/secret')
|
||||||
|
assert_equal 401, status
|
||||||
|
assert_equal 'no token', body.join
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_before_action_except_skips_the_named_action
|
||||||
|
status, _, body = call('GET', '/public')
|
||||||
|
assert_equal 200, status
|
||||||
|
assert JSON.parse(body.join)['reached']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_halted_before_action_prevents_the_action_body_from_running
|
||||||
|
status, _, body = call('GET', '/secret')
|
||||||
|
refute_equal 200, status
|
||||||
|
refute_includes body.join, 'reached'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_after_action_runs_when_before_action_passes
|
||||||
|
call('GET', '/secret?token=ok')
|
||||||
|
assert_includes FilterController.after_log, 'secret'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_after_action_except_is_honored
|
||||||
|
call('GET', '/public')
|
||||||
|
refute_includes FilterController.after_log, 'public_action'
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in new issue
Block a user