spyke 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+ require 'test_helper'
2
+
3
+ module Spyke
4
+ class AttributesTest < MiniTest::Test
5
+ def test_predicate_methods
6
+ stub_request(:get, 'http://sushi.com/recipes/1').to_return_json(data: { id: 1, title: 'Sushi' })
7
+
8
+ recipe = Recipe.find(1)
9
+
10
+ assert_equal true, recipe.title?
11
+ assert_equal false, recipe.description?
12
+ end
13
+
14
+ def test_respond_to
15
+ stub_request(:get, 'http://sushi.com/recipes/1').to_return_json(data: { id: 1, serves: 3 })
16
+
17
+ recipe = Recipe.find(1)
18
+
19
+ assert_equal true, recipe.respond_to?(:serves)
20
+ assert_equal false, recipe.respond_to?(:story)
21
+ end
22
+
23
+ def test_assigning_attributes
24
+ recipe = Recipe.new(id: 2)
25
+ recipe.attributes = { title: 'Pasta' }
26
+
27
+ assert_equal 'Pasta', recipe.title
28
+ assert_equal 2, recipe.id
29
+ end
30
+
31
+ def test_removing_id_if_blank_string
32
+ recipe = Recipe.new
33
+
34
+ assert_nil recipe.id
35
+ assert_equal({ 'recipe' => {} }, recipe.to_params)
36
+
37
+ recipe.id = ''
38
+ assert_nil recipe.id
39
+ assert_equal({ 'recipe' => {} }, recipe.to_params)
40
+ end
41
+
42
+ def test_setters
43
+ recipe = Recipe.new
44
+ recipe.title = 'Sushi'
45
+ assert_equal 'Sushi', recipe.title
46
+ end
47
+
48
+ def test_equality
49
+ assert_equal Recipe.new(id: 2, title: 'Fish'), Recipe.new(id: 2, title: 'Fish')
50
+ refute_equal Recipe.new(id: 2, title: 'Fish'), Recipe.new(id: 1, title: 'Fish')
51
+ refute_equal Recipe.new(id: 2, title: 'Fish'), 'not_a_spyke_object'
52
+ end
53
+
54
+ def test_explicit_attributes
55
+ recipe = Recipe.new
56
+ assert_equal nil, recipe.title
57
+ assert_raises NoMethodError do
58
+ recipe.description
59
+ end
60
+
61
+ recipe = Recipe.new(title: 'Fish')
62
+ assert_equal 'Fish', recipe.title
63
+ end
64
+
65
+ def test_converting_files_to_faraday_io
66
+ Faraday::UploadIO.stubs(:new).with('/photo.jpg', 'image/jpeg').returns('UploadIO')
67
+ file = mock
68
+ file.stubs(:path).returns('/photo.jpg')
69
+ file.stubs(:content_type).returns('image/jpeg')
70
+
71
+ recipe = Recipe.new(image: Image.new(file: file))
72
+
73
+ assert_equal 'UploadIO', recipe.image.to_params['image']['file']
74
+ assert_equal 'UploadIO', recipe.to_params['recipe']['image']['file']
75
+
76
+ recipe = Recipe.new(image_attributes: { file: file })
77
+
78
+ assert_equal 'UploadIO', recipe.image.to_params['image']['file']
79
+ assert_equal 'UploadIO', recipe.to_params['recipe']['image']['file']
80
+ end
81
+
82
+ def test_inspect
83
+ recipe = Recipe.new(id: 2, title: 'Pizza', description: 'Delicious')
84
+ assert_equal '#<Recipe(/recipes/2) id: 2 title: "Pizza" description: "Delicious">', recipe.inspect
85
+ end
86
+
87
+ def test_rejecting_wrong_number_of_args
88
+ skip 'wishlisted'
89
+ stub_request(:any, /.*/)
90
+ recipe = Recipe.new(description: 'Delicious')
91
+ assert_raises ArgumentError do
92
+ recipe.description(2)
93
+ end
94
+ assert_raises ArgumentError do
95
+ recipe.description?(2)
96
+ end
97
+ assert_raises ArgumentError do
98
+ recipe.image(2)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ module Spyke
4
+ class CallbacksTest < MiniTest::Test
5
+ def setup
6
+ stub_request(:any, /.*/)
7
+ end
8
+
9
+ def test_before_save
10
+ Recipe.any_instance.expects(:before_save_callback)
11
+ Recipe.create
12
+ end
13
+
14
+ def test_before_create
15
+ Recipe.any_instance.expects(:before_create_callback)
16
+ Recipe.create
17
+ end
18
+
19
+ def test_before_update
20
+ Recipe.any_instance.expects(:before_update_callback)
21
+ Recipe.new(id: 1).save
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,53 @@
1
+ require 'test_helper'
2
+
3
+ module Spyke
4
+ class CustomRequestTest < MiniTest::Test
5
+ def test_custom_get_request_from_class
6
+ endpoint = stub_request(:get, 'http://sushi.com/recipes/recent').to_return_json(data: [{ id: 1, title: 'Bread' }])
7
+ assert_equal %w{ Bread }, Recipe.get('/recipes/recent').map(&:title)
8
+ assert_requested endpoint
9
+ end
10
+
11
+ def test_get_request_with_prepended_scope
12
+ skip 'wishlisted'
13
+ endpoint = stub_request(:get, 'http://sushi.com/recipes/recent?status=published')
14
+ Recipe.published.get('/recipes/recent')
15
+ assert_requested endpoint
16
+ end
17
+
18
+ def test_get_request_with_appended_scope
19
+ skip 'wishlisted'
20
+ endpoint = stub_request(:get, 'http://sushi.com/recipes/recent?status=published')
21
+ Recipe.get('/recipes/recent').published.fetch
22
+ assert_requested endpoint
23
+ end
24
+
25
+ def test_custom_get_request_from_class
26
+ endpoint = stub_request(:get, 'http://sushi.com/recipes/recent').to_return_json(data: [{ id: 1, title: 'Bread' }])
27
+ assert_equal %w{ Bread }, Recipe.get('/recipes/recent').map(&:title)
28
+ assert_requested endpoint
29
+ end
30
+
31
+ def test_custom_put_request_from_class
32
+ endpoint = stub_request(:put, 'http://sushi.com/recipes/1/publish')
33
+ Recipe.put('/recipes/1/publish')
34
+ assert_requested endpoint
35
+ end
36
+
37
+ def test_custom_put_request_from_instance
38
+ endpoint = stub_request(:put, 'http://sushi.com/recipes/1/publish').to_return_json(data: { id: 1, status: 'published' })
39
+ recipe = Recipe.new(id: 1, status: 'unpublished')
40
+ recipe.put('/recipes/:id/publish')
41
+
42
+ assert_equal 'published', recipe.status
43
+ assert_requested endpoint
44
+ end
45
+
46
+ def test_custom_put_request_from_instance_with_symbol
47
+ endpoint = stub_request(:put, 'http://sushi.com/recipes/1/draft')
48
+ recipe = Recipe.new(id: 1)
49
+ recipe.put(:draft)
50
+ assert_requested endpoint
51
+ end
52
+ end
53
+ end
data/test/orm_test.rb ADDED
@@ -0,0 +1,136 @@
1
+ require 'test_helper'
2
+
3
+ module Spyke
4
+ class OrmTest < MiniTest::Test
5
+ def test_find
6
+ stub_request(:get, 'http://sushi.com/recipes/1').to_return_json(data: { id: 1, title: 'Sushi' })
7
+ stub_request(:get, 'http://sushi.com/users/1').to_return_json(data: { id: 1, name: 'Bob' })
8
+
9
+ recipe = Recipe.find(1)
10
+ user = User.find(1)
11
+
12
+ assert_equal 1, recipe.id
13
+ assert_equal 'Sushi', recipe.title
14
+ assert_equal 'Bob', user.name
15
+ end
16
+
17
+ def test_reload
18
+ stub_request(:get, 'http://sushi.com/recipes/1').to_return_json(data: { id: 1, title: 'Sushi' })
19
+
20
+ recipe = Recipe.find(1)
21
+ assert_equal 'Sushi', recipe.title
22
+
23
+ stub_request(:get, 'http://sushi.com/recipes/1').to_return_json(data: { id: 1, title: 'Sashimi' })
24
+ recipe.reload
25
+ assert_equal 'Sashimi', recipe.title
26
+ end
27
+
28
+ def test_find_with_slug
29
+ endpoint = stub_request(:get, 'http://sushi.com/recipes/1').to_return_json(data: { id: 1 })
30
+ Recipe.find('1-delicious-soup')
31
+ assert_requested endpoint
32
+ end
33
+
34
+ def test_404
35
+ stub_request(:get, 'http://sushi.com/recipes/1').to_return(status: 404, body: { message: 'Not found' }.to_json)
36
+
37
+ assert_raises ResourceNotFound do
38
+ Recipe.find(1)
39
+ end
40
+ end
41
+
42
+ def test_save_new_record
43
+ endpoint = stub_request(:post, 'http://sushi.com/recipes').with(body: { recipe: { title: 'Sushi' } }).to_return_json(data: { id: 1, title: 'Sushi (created)' })
44
+
45
+ recipe = Recipe.new(title: 'Sushi')
46
+ recipe.save
47
+
48
+ assert_equal 'Sushi (created)', recipe.title
49
+ assert_requested endpoint
50
+ end
51
+
52
+ def test_save_persisted_record
53
+ stub_request(:put, /.*/)
54
+ endpoint = stub_request(:put, 'http://sushi.com/recipes/1').with(body: { recipe: { title: 'Sushi' } }).to_return_json(data: { id: 1, title: 'Sushi (saved)' })
55
+
56
+ recipe = Recipe.new(id: 1, title: 'Sashimi')
57
+ recipe.title = 'Sushi'
58
+ recipe.save
59
+
60
+ assert_equal 'Sushi (saved)', recipe.title
61
+ assert_requested endpoint
62
+ end
63
+
64
+ def test_create
65
+ endpoint = stub_request(:post, 'http://sushi.com/recipes').with(body: { recipe: { title: 'Sushi' } }).to_return_json(data: { id: 1, title: 'Sushi' })
66
+
67
+ recipe = Recipe.create(title: 'Sushi')
68
+
69
+ assert_equal 'Sushi', recipe.title
70
+ assert_requested endpoint
71
+ end
72
+
73
+ def test_find_using_custom_uri_template
74
+ endpoint = stub_request(:get, 'http://sushi.com/images/photos/1').to_return_json(data: { id: 1 })
75
+ Photo.find(1)
76
+ assert_requested endpoint
77
+ end
78
+
79
+ def test_create_using_custom_uri_template
80
+ endpoint = stub_request(:post, 'http://sushi.com/images/photos')
81
+ Photo.create
82
+ assert_requested endpoint
83
+ end
84
+
85
+ def test_create_using_nested_custom_uri_template
86
+ endpoint = stub_request(:post, 'http://sushi.com/recipes/1/ingredients')
87
+ Ingredient.new(recipe_id: 1).save
88
+ assert_requested endpoint
89
+ end
90
+
91
+ def test_create_using_custom_method
92
+ endpoint = stub_request(:put, 'http://sushi.com/images')
93
+ Image.create
94
+ assert_requested endpoint
95
+ end
96
+
97
+ def test_inheritance_using_custom_method
98
+ endpoint = stub_request(:put, 'http://sushi.com/step_images')
99
+ StepImage.create
100
+ assert_requested endpoint
101
+ end
102
+
103
+ def test_non_nested_params
104
+ assert_equal({ 'url' => 'bob.jpg' }, RecipeImage.new(url: 'bob.jpg').to_params)
105
+ end
106
+
107
+ def test_destroy
108
+ endpoint = stub_request(:delete, 'http://sushi.com/recipes/1')
109
+ Recipe.new(id: 1).destroy
110
+ assert_requested endpoint
111
+ end
112
+
113
+ def test_destroy_class_method
114
+ endpoint = stub_request(:delete, 'http://sushi.com/recipes/1')
115
+ Recipe.destroy(1)
116
+ assert_requested endpoint
117
+ end
118
+
119
+ def test_scoped_destroy_class_method
120
+ endpoint = stub_request(:delete, 'http://sushi.com/recipes/1/ingredients/2')
121
+ Ingredient.where(recipe_id: 1).destroy(2)
122
+ assert_requested endpoint
123
+ end
124
+
125
+ def test_scoped_destroy_class_method_without_param
126
+ endpoint = stub_request(:delete, 'http://sushi.com/recipes/1/image')
127
+ RecipeImage.where(recipe_id: 1).destroy
128
+ assert_requested endpoint
129
+ end
130
+
131
+ def test_validations
132
+ assert_equal false, RecipeImage.new.valid?
133
+ assert_equal true, RecipeImage.new(url: 'bob.jpg').valid?
134
+ end
135
+ end
136
+ end
data/test/path_test.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'test_helper'
2
+
3
+ module Spyke
4
+ class PathTest < MiniTest::Test
5
+ def test_collection_path
6
+ assert_equal '/recipes', Path.new('/recipes/:id').to_s
7
+ end
8
+
9
+ def test_resource_path
10
+ assert_equal '/recipes/2', Path.new('/recipes/:id', id: 2).to_s
11
+ end
12
+
13
+ def test_nested_collection_path
14
+ path = Path.new('/users/:user_id/recipes/:id', user_id: 1, status: 'published')
15
+ assert_equal [:user_id, :id], path.variables
16
+ assert_equal '/users/1/recipes', path.to_s
17
+ end
18
+
19
+ def test_nested_resource_path
20
+ assert_equal '/users/1/recipes/2', Path.new('/users/:user_id/recipes/:id', user_id: 1, id: 2).to_s
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,76 @@
1
+ require 'test_helper'
2
+
3
+ module Spyke
4
+ class RelationTest < MiniTest::Test
5
+ def test_all
6
+ stub_request(:get, 'http://sushi.com/recipes').to_return_json(data: [{ id: 1, title: 'Sushi' }, { id: 2, title: 'Nigiri' }], metadata: 'meta')
7
+
8
+ recipes = Recipe.all
9
+
10
+ assert_equal %w{ Sushi Nigiri }, recipes.map(&:title)
11
+ assert_equal [1, 2], recipes.map(&:id)
12
+ assert_equal 'meta', recipes.metadata
13
+ end
14
+
15
+ def test_chainable_where
16
+ endpoint = stub_request(:get, 'http://sushi.com/recipes?status=published&per_page=3')
17
+
18
+ Recipe.where(status: 'published').where(per_page: 3).to_a
19
+
20
+ assert_requested endpoint
21
+ end
22
+
23
+ def test_chainable_class_method
24
+ endpoint = stub_request(:get, 'http://sushi.com/recipes?status=published&per_page=3')
25
+
26
+ Recipe.where(per_page: 3).published.to_a
27
+
28
+ assert_requested endpoint
29
+ end
30
+
31
+ def test_prepended_chainable_class_method
32
+ endpoint = stub_request(:get, 'http://sushi.com/recipes?status=published&per_page=3')
33
+
34
+ Recipe.published.where(per_page: 3).to_a
35
+
36
+ assert_requested endpoint
37
+ end
38
+
39
+ def test_scope_class_method
40
+ endpoint = stub_request(:get, 'http://sushi.com/recipes?status=published&page=3')
41
+
42
+ Recipe.published.page(3).to_a
43
+ assert_requested endpoint
44
+ end
45
+
46
+ def test_scope_doesnt_get_stuck
47
+ endpoint_1 = stub_request(:get, 'http://sushi.com/recipes?per_page=3&status=published')
48
+ endpoint_2 = stub_request(:get, 'http://sushi.com/recipes?status=published')
49
+
50
+ Recipe.where(status: 'published').where(per_page: 3).to_a
51
+ Recipe.where(status: 'published').to_a
52
+ assert_requested endpoint_1
53
+ assert_requested endpoint_2
54
+ end
55
+
56
+ def test_create_scoped
57
+ endpoint = stub_request(:post, 'http://sushi.com/recipes').with(body: { recipe: { title: 'Sushi', status: 'published' } })
58
+
59
+ Recipe.published.create(title: 'Sushi')
60
+
61
+ assert_requested endpoint
62
+ end
63
+
64
+ def test_cached_result
65
+ endpoint_1 = stub_request(:get, 'http://sushi.com/recipes?status=published&per_page=3')
66
+ endpoint_2 = stub_request(:get, 'http://sushi.com/recipes?status=published')
67
+
68
+ recipes = Recipe.published.where(per_page: 3)
69
+ recipes.any?
70
+ recipes.to_a
71
+ assert_requested endpoint_1, times: 1
72
+ Recipe.published.to_a
73
+ assert_requested endpoint_2, times: 1
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,6 @@
1
+ # Set up dummy api
2
+ Spyke::Config.connection = Faraday.new(url: 'http://sushi.com') do |faraday|
3
+ faraday.request :json
4
+ faraday.response :json
5
+ faraday.adapter Faraday.default_adapter
6
+ end
@@ -0,0 +1,65 @@
1
+ class Recipe < Spyke::Base
2
+ has_many :groups
3
+ has_one :image
4
+ has_one :background_image, class_name: 'Image', uri: nil
5
+ has_one :alternate, class_name: 'Recipe', uri: '/recipes/:recipe_id/alternates/recipe'
6
+ belongs_to :user
7
+
8
+ scope :published, -> { where(status: 'published') }
9
+ attributes :title
10
+
11
+ before_save :before_save_callback
12
+ before_create :before_create_callback
13
+ before_update :before_update_callback
14
+
15
+ accepts_nested_attributes_for :image, :user, :groups
16
+
17
+ def self.page(number)
18
+ if number.present?
19
+ where(page: number)
20
+ else
21
+ all
22
+ end
23
+ end
24
+
25
+ def ingredients
26
+ groups.first.ingredients
27
+ end
28
+
29
+ private
30
+
31
+ def before_create_callback; end
32
+ def before_update_callback; end
33
+ def before_save_callback; end
34
+ end
35
+
36
+ class Image < Spyke::Base
37
+ method_for :create, :put
38
+ end
39
+
40
+ class StepImage < Image
41
+ end
42
+
43
+ class RecipeImage < Image
44
+ uri '/recipes/:recipe_id/image'
45
+ validates :url, presence: true
46
+ attributes :url
47
+ include_root_in_json false
48
+ end
49
+
50
+ class Group < Spyke::Base
51
+ has_many :ingredients, uri: nil
52
+ accepts_nested_attributes_for :ingredients
53
+ end
54
+
55
+ class Ingredient < Spyke::Base
56
+ uri '/recipes/:recipe_id/ingredients/:id'
57
+ end
58
+
59
+ class User < Spyke::Base
60
+ has_many :recipes
61
+ end
62
+
63
+ class Photo < Spyke::Base
64
+ uri '/images/photos/:id'
65
+ end