Add better serialization_scope tests; uncover bug

This commit is contained in:
Benjamin Fleischer 2016-02-10 00:44:06 -06:00
parent 26b089c881
commit 85658c0230
2 changed files with 214 additions and 54 deletions

View File

@ -96,6 +96,8 @@ module ActiveModel
_serializer_instance_methods.include?(name)
end
# TODO: Fix load-order failures when different serializer instances define different
# scope methods
def self._serializer_instance_methods
@_serializer_instance_methods ||= (public_instance_methods - Object.public_instance_methods).to_set
end

View File

@ -1,63 +1,221 @@
require 'test_helper'
require 'pathname'
class DefaultScopeNameTest < ActionController::TestCase
class UserSerializer < ActiveModel::Serializer
module SerializationScopeTesting
class User < ActiveModelSerializers::Model
attr_accessor :id, :name, :admin
def admin?
current_user.admin
end
attributes :admin?
end
class UserTestController < ActionController::Base
protect_from_forgery
before_action { request.format = :json }
def current_user
User.new(id: 1, name: 'Pete', admin: false)
end
def render_new_user
render json: User.new(id: 1, name: 'Pete', admin: false), serializer: UserSerializer, adapter: :json_api
admin
end
end
class Comment < ActiveModelSerializers::Model
attr_accessor :id, :body
end
class Post < ActiveModelSerializers::Model
attr_accessor :id, :title, :body, :comments
end
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :body, :comments
tests UserTestController
def body
"The 'scope' is the 'current_user': #{scope == current_user}"
end
def test_default_scope_name
get :render_new_user
assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":false}}}', @response.body
end
end
class SerializationScopeNameTest < ActionController::TestCase
class AdminUserSerializer < ActiveModel::Serializer
def admin?
current_admin.admin
end
attributes :admin?
end
class AdminUserTestController < ActionController::Base
protect_from_forgery
serialization_scope :current_admin
before_action { request.format = :json }
def current_admin
User.new(id: 2, name: 'Bob', admin: true)
end
def render_new_user
render json: User.new(id: 1, name: 'Pete', admin: false), serializer: AdminUserSerializer, adapter: :json_api
end
end
tests AdminUserTestController
def test_override_scope_name_with_controller
get :render_new_user
assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":true}}}', @response.body
def comments
if current_user.admin?
[Comment.new(id: 1, body: 'Admin')]
else
[Comment.new(id: 2, body: 'Scoped')]
end
end
def json_key
'post'
end
end
class PostTestController < ActionController::Base
attr_accessor :current_user
def render_post_by_non_admin
self.current_user = User.new(id: 3, name: 'Pete', admin: false)
render json: new_post, serializer: serializer, adapter: :json
end
def render_post_by_admin
self.current_user = User.new(id: 3, name: 'Pete', admin: true)
render json: new_post, serializer: serializer, adapter: :json
end
private
def new_post
Post.new(id: 4, title: 'Title')
end
def serializer
PostSerializer
end
end
class PostViewContextSerializer < PostSerializer
def body
"The 'scope' is the 'view_context': #{scope == view_context}"
end
def comments
if view_context.controller.current_user.admin?
[Comment.new(id: 1, body: 'Admin')]
else
[Comment.new(id: 2, body: 'Scoped')]
end
end
end
class DefaultScopeTest < ActionController::TestCase
tests PostTestController
def test_default_serialization_scope
assert_equal :current_user, @controller._serialization_scope
end
def test_default_serialization_scope_object
assert_equal @controller.current_user, @controller.serialization_scope
end
def test_default_scope_non_admin
get :render_post_by_non_admin
expected_json = {
post: {
id: 4,
title: 'Title',
body: "The 'scope' is the 'current_user': true",
comments: [
{ id: 2, body: 'Scoped' }
]
}
}.to_json
assert_equal expected_json, @response.body
end
def test_default_scope_admin
get :render_post_by_admin
expected_json = {
post: {
id: 4,
title: 'Title',
body: "The 'scope' is the 'current_user': true",
comments: [
{ id: 1, body: 'Admin' }
]
}
}.to_json
assert_equal expected_json, @response.body
end
end
class SerializationScopeTest < ActionController::TestCase
class PostViewContextTestController < PostTestController
serialization_scope :view_context
private
def serializer
PostViewContextSerializer
end
end
tests PostViewContextTestController
def test_defined_serialization_scope
assert_equal :view_context, @controller._serialization_scope
end
def test_defined_serialization_scope_object
assert_equal @controller.view_context.class, @controller.serialization_scope.class
end
def test_serialization_scope_non_admin
get :render_post_by_non_admin
expected_json = {
post: {
id: 4,
title: 'Title',
body: "The 'scope' is the 'view_context': true",
comments: [
{ id: 2, body: 'Scoped' }
]
}
}.to_json
assert_equal expected_json, @response.body
end
def test_serialization_scope_admin
get :render_post_by_admin
expected_json = {
post: {
id: 4,
title: 'Title',
body: "The 'scope' is the 'view_context': true",
comments: [
{ id: 1, body: 'Admin' }
]
}
}.to_json
assert_equal expected_json, @response.body
end
end
class NilSerializationScopeTest < ActionController::TestCase
class PostViewContextTestController < ActionController::Base
serialization_scope nil
attr_accessor :current_user
def render_post_with_no_scope
self.current_user = User.new(id: 3, name: 'Pete', admin: false)
render json: new_post, serializer: PostSerializer, adapter: :json
end
# TODO: run test when
# global state in Serializer._serializer_instance_methods is fixed
# def render_post_with_passed_in_scope
# self.current_user = User.new(id: 3, name: 'Pete', admin: false)
# render json: new_post, serializer: PostSerializer, adapter: :json, scope: current_user, scope_name: :current_user
# end
private
def new_post
Post.new(id: 4, title: 'Title')
end
end
tests PostViewContextTestController
def test_nil_serialization_scope
assert_nil @controller._serialization_scope
end
def test_nil_serialization_scope_object
assert_nil @controller.serialization_scope
end
# TODO: change to NoMethodError and match 'admin?' when the
# global state in Serializer._serializer_instance_methods is fixed
def test_nil_scope
exception = assert_raises(NameError) do
get :render_post_with_no_scope
end
assert_match(/admin|current_user/, exception.message)
end
# TODO: run test when
# global state in Serializer._serializer_instance_methods is fixed
# def test_nil_scope_passed_in_current_user
# get :render_post_with_passed_in_scope
# expected_json = {
# post: {
# id: 4,
# title: 'Title',
# body: "The 'scope' is the 'current_user': true",
# comments: [
# { id: 2, body: 'Scoped' }
# ]
# }
# }.to_json
# assert_equal expected_json, @response.body
# end
end
end