ddy_remote_resource 0.4.11 → 1.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Guardfile +3 -0
- data/lib/remote_resource.rb +77 -34
- data/lib/remote_resource/base.rb +20 -8
- data/lib/remote_resource/connection.rb +26 -5
- data/lib/remote_resource/connection_options.rb +5 -3
- data/lib/remote_resource/querying/finder_methods.rb +3 -3
- data/lib/remote_resource/querying/persistence_methods.rb +17 -12
- data/lib/remote_resource/request.rb +96 -62
- data/lib/remote_resource/response.rb +5 -1
- data/lib/remote_resource/rest.rb +13 -17
- data/lib/remote_resource/url_naming.rb +4 -10
- data/lib/remote_resource/url_naming_determination.rb +1 -3
- data/lib/remote_resource/util.rb +64 -0
- data/lib/remote_resource/version.rb +1 -1
- data/remote_resource.gemspec +2 -2
- data/spec/fixtures/text_file.txt +1 -0
- data/spec/integration/all_spec.rb +166 -0
- data/spec/integration/collection_prefix_spec.rb +99 -0
- data/spec/integration/create_spec.rb +181 -0
- data/spec/integration/destroy_spec.rb +252 -0
- data/spec/integration/find_by_spec.rb +168 -0
- data/spec/integration/find_spec.rb +139 -0
- data/spec/integration/headers_spec.rb +222 -0
- data/spec/integration/naming_spec.rb +138 -0
- data/spec/integration/save_spec.rb +320 -0
- data/spec/integration/update_attributes_spec.rb +221 -0
- data/spec/integration/where_spec.rb +152 -0
- data/spec/lib/extensions/ethon/easy/queryable_spec.rb +4 -4
- data/spec/lib/remote_resource/base_spec.rb +54 -110
- data/spec/lib/remote_resource/builder_spec.rb +1 -1
- data/spec/lib/remote_resource/collection_spec.rb +1 -1
- data/spec/lib/remote_resource/connection_options_spec.rb +20 -17
- data/spec/lib/remote_resource/connection_spec.rb +36 -27
- data/spec/lib/remote_resource/querying/finder_methods_spec.rb +199 -72
- data/spec/lib/remote_resource/querying/persistence_methods_spec.rb +228 -220
- data/spec/lib/remote_resource/request_spec.rb +313 -342
- data/spec/lib/remote_resource/response_spec.rb +9 -3
- data/spec/lib/remote_resource/rest_spec.rb +11 -11
- data/spec/lib/remote_resource/url_naming_determination_spec.rb +1 -1
- data/spec/lib/remote_resource/url_naming_spec.rb +7 -22
- data/spec/lib/remote_resource/util_spec.rb +56 -0
- data/spec/lib/remote_resource/version_spec.rb +2 -3
- data/spec/spec_helper.rb +37 -0
- metadata +33 -22
- data/lib/remote_resource/http_errors.rb +0 -33
- data/lib/remote_resource/response_handeling.rb +0 -48
@@ -26,6 +26,10 @@ module RemoteResource
|
|
26
26
|
original_response.response_code
|
27
27
|
end
|
28
28
|
|
29
|
+
def response_headers
|
30
|
+
original_response.headers
|
31
|
+
end
|
32
|
+
|
29
33
|
def sanitized_response_body
|
30
34
|
return empty_hash if response_body.blank?
|
31
35
|
return empty_hash if parsed_response_body.blank?
|
@@ -75,4 +79,4 @@ module RemoteResource
|
|
75
79
|
end
|
76
80
|
|
77
81
|
end
|
78
|
-
end
|
82
|
+
end
|
data/lib/remote_resource/rest.rb
CHANGED
@@ -1,28 +1,24 @@
|
|
1
1
|
module RemoteResource
|
2
2
|
module REST
|
3
|
-
extend ActiveSupport::Concern
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
def get(attributes = {}, connection_options = {})
|
5
|
+
RemoteResource::Request.new(self, __method__, attributes, connection_options).perform
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
connection_options = args[1] || {}
|
8
|
+
def put(attributes = {}, connection_options = {})
|
9
|
+
RemoteResource::Request.new(self, __method__, attributes, connection_options).perform
|
10
|
+
end
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
end
|
12
|
+
def patch(attributes = {}, connection_options = {})
|
13
|
+
RemoteResource::Request.new(self, __method__, attributes, connection_options).perform
|
17
14
|
end
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
connection_options = args[1] || {}
|
16
|
+
def post(attributes = {}, connection_options = {})
|
17
|
+
RemoteResource::Request.new(self, __method__, attributes, connection_options).perform
|
18
|
+
end
|
23
19
|
|
24
|
-
|
25
|
-
|
20
|
+
def delete(attributes = {}, connection_options = {})
|
21
|
+
RemoteResource::Request.new(self, __method__, attributes, connection_options).perform
|
26
22
|
end
|
27
23
|
|
28
24
|
end
|
@@ -10,25 +10,19 @@ module RemoteResource
|
|
10
10
|
|
11
11
|
module ClassMethods
|
12
12
|
|
13
|
-
def app_host(
|
14
|
-
|
13
|
+
def app_host(*_)
|
14
|
+
warn '[DEPRECATION] `.app_host` is deprecated. Please use a different method to determine the site.'
|
15
15
|
end
|
16
16
|
|
17
17
|
def base_url
|
18
|
-
|
18
|
+
warn '[DEPRECATION] `.base_url` is deprecated. Please use the connection_options[:base_url] when querying instead.'
|
19
19
|
end
|
20
20
|
|
21
21
|
def use_relative_model_naming?
|
22
22
|
true
|
23
23
|
end
|
24
24
|
|
25
|
-
private
|
26
|
-
|
27
|
-
def determined_url_naming
|
28
|
-
RemoteResource::UrlNamingDetermination.new self
|
29
|
-
end
|
30
|
-
|
31
25
|
end
|
32
26
|
|
33
27
|
end
|
34
|
-
end
|
28
|
+
end
|
@@ -14,9 +14,7 @@ module RemoteResource
|
|
14
14
|
path_prefix = connection_options.fetch(:path_prefix, resource_klass.path_prefix)
|
15
15
|
path_postfix = connection_options.fetch(:path_postfix, resource_klass.path_postfix)
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
"#{site}#{version.presence}#{path_prefix.presence}#{collection_prefix(check_collection_options)}/#{url_safe_relative_name}#{id}#{path_postfix.presence}"
|
17
|
+
File.join(site.to_s, version.to_s, path_prefix.to_s, collection_prefix(check_collection_options).to_s, url_safe_relative_name, id.to_s, path_postfix.to_s).chomp('/')
|
20
18
|
end
|
21
19
|
|
22
20
|
def collection_prefix(check_collection_options)
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module RemoteResource
|
2
|
+
module Util
|
3
|
+
|
4
|
+
FILTERED = '[FILTERED]'.freeze
|
5
|
+
|
6
|
+
def self.filter_params(query_string_or_json_body, filtered_params:)
|
7
|
+
filtered = query_string_or_json_body
|
8
|
+
filtered_params.each do |filtered_param|
|
9
|
+
filtered = filtered.to_s.gsub(/(?<="#{filtered_param}":|#{filtered_param}=)(.*?)(?=,|}|&|$)/, FILTERED)
|
10
|
+
end
|
11
|
+
filtered
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.encode_params_to_query(params)
|
15
|
+
if params.is_a?(String)
|
16
|
+
pairs = [params]
|
17
|
+
else
|
18
|
+
pairs = recursively_generate_query(params, nil)
|
19
|
+
end
|
20
|
+
|
21
|
+
URI.encode_www_form(pairs)
|
22
|
+
end
|
23
|
+
|
24
|
+
# This method is based on the monkey patched method:
|
25
|
+
# Ethon::Easy::Queryable#recursively_generate_pairs
|
26
|
+
#
|
27
|
+
# The monkey patch was needed to pass Array
|
28
|
+
# params without an index.
|
29
|
+
#
|
30
|
+
# The problem is described in typhoeus/typhoeus issue #320:
|
31
|
+
# https://github.com/typhoeus/typhoeus/issues/320
|
32
|
+
#
|
33
|
+
# The fix is described in dylanfareed/ethon commit 548033a:
|
34
|
+
# https://github.com/dylanfareed/ethon/commit/548033a8557a48203b7d49f3f98812bd79bc05e4
|
35
|
+
#
|
36
|
+
def self.recursively_generate_query(component, prefix, pairs = [])
|
37
|
+
case component
|
38
|
+
when Hash
|
39
|
+
component.each do |key, value|
|
40
|
+
key = prefix.nil? ? key : "#{prefix}[#{key}]"
|
41
|
+
|
42
|
+
if value.respond_to?(:each)
|
43
|
+
recursively_generate_query(value, key, pairs)
|
44
|
+
else
|
45
|
+
pairs.push([key, value.to_s])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
when Array
|
49
|
+
component.each do |value|
|
50
|
+
key = "#{prefix}[]"
|
51
|
+
|
52
|
+
if value.respond_to?(:each)
|
53
|
+
recursively_generate_query(value, key, pairs)
|
54
|
+
else
|
55
|
+
pairs.push([key, value.to_s])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
pairs
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/remote_resource.gemspec
CHANGED
@@ -22,10 +22,10 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency 'rake', '~> 10.4'
|
23
23
|
spec.add_development_dependency 'rspec', '~> 3.1'
|
24
24
|
spec.add_development_dependency 'pry', '~> 0.10'
|
25
|
-
spec.add_development_dependency 'webmock', '~> 1.24'
|
25
|
+
# spec.add_development_dependency 'webmock', '~> 1.24'
|
26
26
|
spec.add_development_dependency 'guard', '~> 2.14'
|
27
27
|
spec.add_development_dependency 'guard-rspec', '~> 4.7'
|
28
|
-
spec.add_development_dependency 'terminal-notifier-guard', '~> 1.6
|
28
|
+
spec.add_development_dependency 'terminal-notifier-guard', '~> 1.6'
|
29
29
|
|
30
30
|
spec.add_runtime_dependency 'activesupport', '~> 4.1'
|
31
31
|
spec.add_runtime_dependency 'activemodel', '~> 4.1'
|
@@ -0,0 +1 @@
|
|
1
|
+
Hello world!
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe '.all' do
|
4
|
+
|
5
|
+
class Post
|
6
|
+
include RemoteResource::Base
|
7
|
+
|
8
|
+
self.site = 'https://www.example.com'
|
9
|
+
self.collection = true
|
10
|
+
self.root_element = :data
|
11
|
+
|
12
|
+
attribute :title, String
|
13
|
+
attribute :body, String
|
14
|
+
attribute :created_at, Time
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:response_body) do
|
18
|
+
{
|
19
|
+
data: [
|
20
|
+
{
|
21
|
+
id: 12,
|
22
|
+
title: 'Lorem Ipsum',
|
23
|
+
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
24
|
+
created_at: Time.new(2015, 10, 4, 9, 30, 0),
|
25
|
+
},
|
26
|
+
{
|
27
|
+
id: 14,
|
28
|
+
title: 'Mauris Purus',
|
29
|
+
body: 'Mauris purus urna, ultrices et suscipit ut, faucibus eget mauris.',
|
30
|
+
created_at: Time.new(2015, 12, 11, 11, 32, 0),
|
31
|
+
},
|
32
|
+
{
|
33
|
+
id: 16,
|
34
|
+
title: 'Vestibulum Commodo',
|
35
|
+
body: 'Vestibulum commodo fringilla suscipit.',
|
36
|
+
created_at: Time.new(2016, 2, 6, 18, 45, 0),
|
37
|
+
},
|
38
|
+
]
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:expected_default_headers) do
|
43
|
+
{ 'Accept' => 'application/json', 'User-Agent' => "RemoteResource #{RemoteResource::VERSION}" }
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'default behaviour' do
|
47
|
+
let!(:expected_request) do
|
48
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts.json')
|
49
|
+
mock_request.with(query: nil, body: nil, headers: expected_default_headers)
|
50
|
+
mock_request.to_return(status: 200, body: response_body.to_json)
|
51
|
+
mock_request
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'performs the correct HTTP GET request' do
|
55
|
+
Post.all
|
56
|
+
expect(expected_request).to have_been_requested
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'builds the correct collection of resources' do
|
60
|
+
posts = Post.all
|
61
|
+
|
62
|
+
aggregate_failures do
|
63
|
+
expect(posts).to respond_to :each
|
64
|
+
expect(posts).to all(be_a(Post))
|
65
|
+
expect(posts.size).to eql 3
|
66
|
+
|
67
|
+
expect(posts[0].id).to eql 12
|
68
|
+
expect(posts[0].title).to eql 'Lorem Ipsum'
|
69
|
+
expect(posts[0].body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
70
|
+
expect(posts[0].created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
|
71
|
+
expect(posts[1].id).to eql 14
|
72
|
+
expect(posts[1].title).to eql 'Mauris Purus'
|
73
|
+
expect(posts[1].body).to eql 'Mauris purus urna, ultrices et suscipit ut, faucibus eget mauris.'
|
74
|
+
expect(posts[1].created_at).to eql Time.new(2015, 12, 11, 11, 32, 0)
|
75
|
+
expect(posts[2].id).to eql 16
|
76
|
+
expect(posts[2].title).to eql 'Vestibulum Commodo'
|
77
|
+
expect(posts[2].body).to eql 'Vestibulum commodo fringilla suscipit.'
|
78
|
+
expect(posts[2].created_at).to eql Time.new(2016, 2, 6, 18, 45, 0)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'with connection_options[:params]' do
|
84
|
+
let!(:expected_request) do
|
85
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts.json')
|
86
|
+
mock_request.with(query: { pseudonym: 'pseudonym' }, body: nil, headers: expected_default_headers)
|
87
|
+
mock_request.to_return(status: 200, body: response_body.to_json)
|
88
|
+
mock_request
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'performs the correct HTTP GET request' do
|
92
|
+
Post.all(params: { pseudonym: 'pseudonym' })
|
93
|
+
expect(expected_request).to have_been_requested
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe 'with connection_options[:headers]' do
|
98
|
+
let!(:expected_request) do
|
99
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts.json')
|
100
|
+
mock_request.with(query: nil, body: nil, headers: expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
101
|
+
mock_request.to_return(status: 200, body: response_body.to_json)
|
102
|
+
mock_request
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'performs the correct HTTP GET request' do
|
106
|
+
Post.all(headers: { 'X-Pseudonym' => 'pseudonym' })
|
107
|
+
expect(expected_request).to have_been_requested
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'with a 404 response' do
|
112
|
+
let!(:expected_request) do
|
113
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts.json')
|
114
|
+
mock_request.with(query: { pseudonym: 'pseudonym' }, body: nil, headers: expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
115
|
+
mock_request.to_return(status: 404)
|
116
|
+
mock_request
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'raises the not found error' do
|
120
|
+
expect { Post.all(params: { pseudonym: 'pseudonym' }, headers: { 'X-Pseudonym' => 'pseudonym' }) }.to raise_error RemoteResource::HTTPNotFound
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'adds metadata to the raised error' do
|
124
|
+
begin
|
125
|
+
Post.all(params: { pseudonym: 'pseudonym' }, headers: { 'X-Pseudonym' => 'pseudonym' })
|
126
|
+
rescue RemoteResource::HTTPNotFound => error
|
127
|
+
aggregate_failures do
|
128
|
+
expect(error.message).to eql 'HTTP request failed for Post with response_code=404 with http_action=get with request_url=https://www.example.com/posts.json'
|
129
|
+
expect(error.request_url).to eql 'https://www.example.com/posts.json'
|
130
|
+
expect(error.response_code).to eql 404
|
131
|
+
expect(error.request_query).to eql(RemoteResource::Util.encode_params_to_query({ pseudonym: 'pseudonym' }))
|
132
|
+
expect(error.request_headers).to eql(expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe 'with a 500 response' do
|
139
|
+
let!(:expected_request) do
|
140
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts.json')
|
141
|
+
mock_request.with(query: { pseudonym: 'pseudonym' }, body: nil, headers: expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
142
|
+
mock_request.to_return(status: 500)
|
143
|
+
mock_request
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'raises the server error' do
|
147
|
+
expect { Post.all(params: { pseudonym: 'pseudonym' }, headers: { 'X-Pseudonym' => 'pseudonym' }) }.to raise_error RemoteResource::HTTPServerError
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'adds metadata to the raised error' do
|
151
|
+
begin
|
152
|
+
Post.all(params: { pseudonym: 'pseudonym' }, headers: { 'X-Pseudonym' => 'pseudonym' })
|
153
|
+
rescue RemoteResource::HTTPServerError => error
|
154
|
+
aggregate_failures do
|
155
|
+
expect(error.message).to eql 'HTTP request failed for Post with response_code=500 with http_action=get with request_url=https://www.example.com/posts.json'
|
156
|
+
expect(error.request_url).to eql 'https://www.example.com/posts.json'
|
157
|
+
expect(error.response_code).to eql 500
|
158
|
+
expect(error.request_query).to eql(RemoteResource::Util.encode_params_to_query({ pseudonym: 'pseudonym' }))
|
159
|
+
expect(error.request_headers).to eql(expected_default_headers.merge({ 'X-Pseudonym' => 'pseudonym' }))
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'connection_options[:collection_prefix] and connection_options[:collection_options]' do
|
4
|
+
|
5
|
+
class Post
|
6
|
+
include RemoteResource::Base
|
7
|
+
|
8
|
+
self.site = 'https://www.example.com'
|
9
|
+
self.collection = true
|
10
|
+
self.root_element = :data
|
11
|
+
|
12
|
+
attribute :title, String
|
13
|
+
attribute :body, String
|
14
|
+
attribute :featured, Boolean
|
15
|
+
attribute :created_at, Time
|
16
|
+
end
|
17
|
+
|
18
|
+
class Comment
|
19
|
+
include RemoteResource::Base
|
20
|
+
|
21
|
+
self.site = 'https://www.example.com'
|
22
|
+
self.collection = true
|
23
|
+
self.collection_prefix = '/posts/:post_id'
|
24
|
+
self.root_element = :data
|
25
|
+
|
26
|
+
attribute :body, String
|
27
|
+
attribute :commented_at, Time
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'connection_options[:collection_prefix] defined on class' do
|
31
|
+
let(:response_body) do
|
32
|
+
{
|
33
|
+
data: {
|
34
|
+
id: 18,
|
35
|
+
body: 'Very interesting comment',
|
36
|
+
commented_at: Time.new(2016, 12, 8, 11, 38, 0)
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
let!(:expected_request) do
|
42
|
+
mock_request = stub_request(:get, 'https://www.example.com/posts/12/comments/18.json')
|
43
|
+
mock_request.to_return(status: 200, body: response_body.to_json)
|
44
|
+
mock_request
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'performs the correct HTTP GET request' do
|
48
|
+
Comment.find(18, collection_options: { post_id: 12 })
|
49
|
+
expect(expected_request).to have_been_requested
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'builds the correct resource' do
|
53
|
+
comment = Comment.find(18, collection_options: { post_id: 12 })
|
54
|
+
|
55
|
+
aggregate_failures do
|
56
|
+
expect(comment.id).to eql 18
|
57
|
+
expect(comment.body).to eql 'Very interesting comment'
|
58
|
+
expect(comment.commented_at).to eql Time.new(2016, 12, 8, 11, 38, 0)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'connection_options[:collection_prefix] given as argument' do
|
64
|
+
let(:response_body) do
|
65
|
+
{
|
66
|
+
data: {
|
67
|
+
id: 12,
|
68
|
+
title: 'Lorem Ipsum',
|
69
|
+
body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
70
|
+
featured: true,
|
71
|
+
created_at: Time.new(2015, 10, 4, 9, 30, 0),
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
let!(:expected_request) do
|
77
|
+
mock_request = stub_request(:get, 'https://www.example.com/users/450/posts/12.json')
|
78
|
+
mock_request.to_return(status: 200, body: response_body.to_json)
|
79
|
+
mock_request
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'performs the correct HTTP GET request' do
|
83
|
+
Post.find(12, collection_prefix: '/users/:user_id', collection_options: { user_id: 450 })
|
84
|
+
expect(expected_request).to have_been_requested
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'builds the correct resource' do
|
88
|
+
post = Post.find(12, collection_prefix: '/users/:user_id', collection_options: { user_id: 450 })
|
89
|
+
|
90
|
+
aggregate_failures do
|
91
|
+
expect(post.id).to eql 12
|
92
|
+
expect(post.title).to eql 'Lorem Ipsum'
|
93
|
+
expect(post.body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
94
|
+
expect(post.created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|