restforce 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of restforce might be problematic. Click here for more details.

Files changed (63) hide show
  1. data/.travis.yml +1 -0
  2. data/CHANGELOG.md +7 -1
  3. data/Gemfile +4 -0
  4. data/Guardfile +11 -0
  5. data/README.md +19 -8
  6. data/lib/restforce.rb +44 -14
  7. data/lib/restforce/abstract_client.rb +9 -0
  8. data/lib/restforce/client.rb +1 -95
  9. data/lib/restforce/{client → concerns}/api.rb +9 -9
  10. data/lib/restforce/{client → concerns}/authentication.rb +9 -9
  11. data/lib/restforce/concerns/base.rb +58 -0
  12. data/lib/restforce/{client → concerns}/caching.rb +4 -4
  13. data/lib/restforce/concerns/canvas.rb +12 -0
  14. data/lib/restforce/{client → concerns}/connection.rb +13 -12
  15. data/lib/restforce/{client → concerns}/picklists.rb +1 -1
  16. data/lib/restforce/{client → concerns}/streaming.rb +3 -3
  17. data/lib/restforce/{client → concerns}/verbs.rb +4 -4
  18. data/lib/restforce/config.rb +40 -10
  19. data/lib/restforce/data/client.rb +18 -0
  20. data/lib/restforce/middleware/authentication.rb +9 -2
  21. data/lib/restforce/sobject.rb +1 -1
  22. data/lib/restforce/tooling/client.rb +13 -0
  23. data/lib/restforce/version.rb +1 -1
  24. data/spec/{lib/client_spec.rb → integration/abstract_client_spec.rb} +21 -214
  25. data/spec/integration/data/client_spec.rb +90 -0
  26. data/spec/spec_helper.rb +0 -14
  27. data/spec/support/client_integration.rb +45 -0
  28. data/spec/support/concerns.rb +18 -0
  29. data/spec/support/event_machine.rb +14 -0
  30. data/spec/support/middleware.rb +18 -1
  31. data/spec/unit/abstract_client_spec.rb +11 -0
  32. data/spec/{lib → unit}/attachment_spec.rb +3 -6
  33. data/spec/unit/collection_spec.rb +50 -0
  34. data/spec/unit/concerns/api_spec.rb +222 -0
  35. data/spec/unit/concerns/authentication_spec.rb +98 -0
  36. data/spec/unit/concerns/base_spec.rb +50 -0
  37. data/spec/unit/concerns/caching_spec.rb +29 -0
  38. data/spec/unit/concerns/canvas_spec.rb +30 -0
  39. data/spec/unit/concerns/connection_spec.rb +14 -0
  40. data/spec/{lib → unit}/config_spec.rb +13 -23
  41. data/spec/unit/data/client_spec.rb +10 -0
  42. data/spec/{lib → unit}/mash_spec.rb +0 -0
  43. data/spec/{lib → unit}/middleware/authentication/password_spec.rb +0 -4
  44. data/spec/{lib → unit}/middleware/authentication/token_spec.rb +0 -4
  45. data/spec/unit/middleware/authentication_spec.rb +67 -0
  46. data/spec/unit/middleware/authorization_spec.rb +11 -0
  47. data/spec/{lib → unit}/middleware/gzip_spec.rb +15 -30
  48. data/spec/unit/middleware/instance_url_spec.rb +24 -0
  49. data/spec/{lib → unit}/middleware/logger_spec.rb +4 -7
  50. data/spec/unit/middleware/mashify_spec.rb +11 -0
  51. data/spec/{lib → unit}/middleware/raise_error_spec.rb +4 -5
  52. data/spec/{lib → unit}/signed_request_spec.rb +0 -0
  53. data/spec/unit/sobject_spec.rb +68 -0
  54. data/spec/unit/tooling/client_spec.rb +7 -0
  55. metadata +75 -46
  56. data/lib/restforce/client/canvas.rb +0 -12
  57. data/spec/lib/collection_spec.rb +0 -52
  58. data/spec/lib/middleware/authentication_spec.rb +0 -69
  59. data/spec/lib/middleware/authorization_spec.rb +0 -17
  60. data/spec/lib/middleware/instance_url_spec.rb +0 -31
  61. data/spec/lib/middleware/mashify_spec.rb +0 -28
  62. data/spec/lib/sobject_spec.rb +0 -122
  63. data/spec/support/basic_client.rb +0 -37
@@ -1,5 +1,5 @@
1
1
  module Restforce
2
- class Client
2
+ module Concerns
3
3
  module Caching
4
4
 
5
5
  # Public: Runs the block with caching disabled.
@@ -8,17 +8,17 @@ module Restforce
8
8
  #
9
9
  # Returns the result of the block
10
10
  def without_caching(&block)
11
- @options[:use_cache] = false
11
+ options[:use_cache] = false
12
12
  block.call
13
13
  ensure
14
- @options.delete(:use_cache)
14
+ options.delete(:use_cache)
15
15
  end
16
16
 
17
17
  private
18
18
 
19
19
  # Internal: Cache to use for the caching middleware
20
20
  def cache
21
- @options[:cache]
21
+ options[:cache]
22
22
  end
23
23
 
24
24
  end
@@ -0,0 +1,12 @@
1
+ module Restforce
2
+ module Concerns
3
+ module Canvas
4
+
5
+ def decode_signed_request(signed_request)
6
+ raise 'client_secret not set.' unless options[:client_secret]
7
+ SignedRequest.decode(signed_request, options[:client_secret])
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
1
  module Restforce
2
- class Client
2
+ module Concerns
3
3
  module Connection
4
4
 
5
5
  # Public: The Faraday::Builder instance used for the middleware stack. This
@@ -14,36 +14,37 @@ module Restforce
14
14
  def middleware
15
15
  connection.builder
16
16
  end
17
+ alias_method :builder, :middleware
17
18
 
18
19
  private
19
20
 
20
21
  # Internal: Internal faraday connection where all requests go through
21
22
  def connection
22
- @connection ||= Faraday.new(@options[:instance_url], connection_options) do |builder|
23
+ @connection ||= Faraday.new(options[:instance_url], connection_options) do |builder|
23
24
  # Parses JSON into Hashie::Mash structures.
24
- builder.use Restforce::Middleware::Mashify, self, @options
25
+ builder.use Restforce::Middleware::Mashify, self, options
25
26
  # Handles multipart file uploads for blobs.
26
27
  builder.use Restforce::Middleware::Multipart
27
28
  # Converts the request into JSON.
28
29
  builder.request :json
29
30
  # Handles reauthentication for 403 responses.
30
- builder.use authentication_middleware, self, @options if authentication_middleware
31
+ builder.use authentication_middleware, self, options if authentication_middleware
31
32
  # Sets the oauth token in the headers.
32
- builder.use Restforce::Middleware::Authorization, self, @options
33
+ builder.use Restforce::Middleware::Authorization, self, options
33
34
  # Ensures the instance url is set.
34
- builder.use Restforce::Middleware::InstanceURL, self, @options
35
+ builder.use Restforce::Middleware::InstanceURL, self, options
35
36
  # Parses returned JSON response into a hash.
36
37
  builder.response :json, :content_type => /\bjson$/
37
38
  # Caches GET requests.
38
- builder.use Restforce::Middleware::Caching, cache, @options if cache
39
+ builder.use Restforce::Middleware::Caching, cache, options if cache
39
40
  # Follows 30x redirects.
40
41
  builder.use FaradayMiddleware::FollowRedirects
41
42
  # Raises errors for 40x responses.
42
43
  builder.use Restforce::Middleware::RaiseError
43
44
  # Log request/responses
44
- builder.use Restforce::Middleware::Logger, Restforce.configuration.logger, @options if Restforce.log?
45
+ builder.use Restforce::Middleware::Logger, Restforce.configuration.logger, options if Restforce.log?
45
46
  # Compress/Decompress the request/response
46
- builder.use Restforce::Middleware::Gzip, self, @options
47
+ builder.use Restforce::Middleware::Gzip, self, options
47
48
 
48
49
  builder.adapter adapter
49
50
  end
@@ -56,9 +57,9 @@ module Restforce
56
57
  # Internal: Faraday Connection options
57
58
  def connection_options
58
59
  { :request => {
59
- :timeout => @options[:timeout],
60
- :open_timeout => @options[:timeout] },
61
- :proxy => @options[:proxy_uri]
60
+ :timeout => options[:timeout],
61
+ :open_timeout => options[:timeout] },
62
+ :proxy => options[:proxy_uri]
62
63
  }
63
64
  end
64
65
 
@@ -1,5 +1,5 @@
1
1
  module Restforce
2
- class Client
2
+ module Concerns
3
3
  module Picklists
4
4
 
5
5
  # Public: Get the available picklist values for a picklist or multipicklist field.
@@ -1,5 +1,5 @@
1
1
  module Restforce
2
- class Client
2
+ module Concerns
3
3
  module Streaming
4
4
 
5
5
  # Public: Subscribe to a PushTopic
@@ -14,8 +14,8 @@ module Restforce
14
14
 
15
15
  # Public: Faye client to use for subscribing to PushTopics
16
16
  def faye
17
- raise 'Instance URL missing. Call .authenticate! first.' unless @options[:instance_url]
18
- @faye ||= Faye::Client.new("#{@options[:instance_url]}/cometd/#{@options[:api_version]}").tap do |client|
17
+ raise 'Instance URL missing. Call .authenticate! first.' unless options[:instance_url]
18
+ @faye ||= Faye::Client.new("#{options[:instance_url]}/cometd/#{options[:api_version]}").tap do |client|
19
19
  client.bind 'transport:down' do
20
20
  Restforce.log "[COMETD DOWN]"
21
21
  client.set_header 'Authorization', "OAuth #{authenticate!.access_token}"
@@ -1,5 +1,5 @@
1
1
  module Restforce
2
- class Client
2
+ module Concerns
3
3
  module Verbs
4
4
 
5
5
  # Internal: Define methods to handle a verb.
@@ -31,13 +31,13 @@ module Restforce
31
31
  # Returns nil.
32
32
  def define_verb(verb)
33
33
  define_method verb do |*args, &block|
34
- retries = @options[:authentication_retries]
34
+ retries = options[:authentication_retries]
35
35
  begin
36
36
  connection.send(verb, *args, &block)
37
37
  rescue Restforce::UnauthorizedError
38
38
  if retries > 0
39
39
  retries -= 1
40
- connection.url_prefix = @options[:instance_url]
40
+ connection.url_prefix = options[:instance_url]
41
41
  retry
42
42
  end
43
43
  raise
@@ -51,7 +51,7 @@ module Restforce
51
51
  # verb - Symbol name of the verb (e.g. :get).
52
52
  #
53
53
  # Examples
54
- #
54
+ #
55
55
  # define_api_verb :get
56
56
  # # => api_get 'sobjects'
57
57
  #
@@ -37,18 +37,48 @@ module Restforce
37
37
  end
38
38
 
39
39
  class Configuration
40
+ class Option
41
+ attr_reader :configuration, :name, :options
42
+
43
+ def self.define(*args)
44
+ new(*args).define
45
+ end
46
+
47
+ def initialize(configuration, name, options = {})
48
+ @configuration, @name, @options = configuration, name, options
49
+ @default = options.fetch(:default, nil)
50
+ end
51
+
52
+ def define
53
+ write_attribute
54
+ define_method if default_provided?
55
+ self
56
+ end
57
+
58
+ private
59
+ attr_reader :default
60
+ alias_method :default_provided?, :default
61
+
62
+ def write_attribute
63
+ configuration.send :attr_accessor, name
64
+ end
65
+
66
+ def define_method
67
+ our_default = default
68
+ our_name = name
69
+ configuration.send :define_method, our_name do
70
+ instance_variable_get(:"@#{our_name}") ||
71
+ instance_variable_set(:"@#{our_name}", our_default.respond_to?(:call) ? our_default.call : our_default)
72
+ end
73
+ end
74
+ end
75
+
40
76
  class << self
41
77
  attr_accessor :options
42
78
 
43
- def option(name, options = {})
44
- default = options.fetch(:default, nil)
45
- attr_accessor name
46
- define_method name do
47
- instance_variable_get(:"@#{name}") ||
48
- instance_variable_set(:"@#{name}", default.respond_to?(:call) ? default.call : default)
49
- end if default
50
- self.options ||= []
51
- self.options << name
79
+ def option(*args)
80
+ option = Option.define(self, *args)
81
+ (self.options ||= []) << option.name
52
82
  end
53
83
  end
54
84
 
@@ -71,7 +101,7 @@ module Restforce
71
101
 
72
102
  # Set this to true if you're authenticating with a Sandbox instance.
73
103
  # Defaults to false.
74
- option :host, :default => 'login.salesforce.com'
104
+ option :host, :default => lambda { ENV['SALESFORCE_HOST'] || 'login.salesforce.com' }
75
105
 
76
106
  option :oauth_token
77
107
  option :refresh_token
@@ -0,0 +1,18 @@
1
+ module Restforce
2
+ module Data
3
+ class Client < AbstractClient
4
+ include Restforce::Concerns::Streaming
5
+ include Restforce::Concerns::Picklists
6
+ include Restforce::Concerns::Canvas
7
+
8
+ # Public: Returns a url to the resource.
9
+ #
10
+ # resource - A record that responds to to_sparam or a String/Fixnum.
11
+ #
12
+ # Returns the url to the resource.
13
+ def url(resource)
14
+ "#{instance_url}/#{(resource.respond_to?(:to_sparam) ? resource.to_sparam : resource)}"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -29,12 +29,13 @@ module Restforce
29
29
 
30
30
  # Internal: The params to post to the OAuth service.
31
31
  def params
32
- raise 'not implemented'
32
+ raise NotImplementedError
33
33
  end
34
34
 
35
35
  # Internal: Faraday connection to use when sending an authentication request.
36
36
  def connection
37
- @connection ||= Faraday.new(:url => "https://#{@options[:host]}") do |builder|
37
+ @connection ||= Faraday.new(faraday_options) do |builder|
38
+ builder.use Faraday::Request::UrlEncoded
38
39
  builder.use Restforce::Middleware::Mashify, nil, @options
39
40
  builder.response :json
40
41
  builder.use Restforce::Middleware::Logger, Restforce.configuration.logger, @options if Restforce.log?
@@ -59,5 +60,11 @@ module Restforce
59
60
  end.join('&')
60
61
  end
61
62
  end
63
+
64
+ private
65
+ def faraday_options
66
+ { :url => "https://#{@options[:host]}",
67
+ :proxy => @options[:proxy_uri] }.reject { |k, v| v.nil? }
68
+ end
62
69
  end
63
70
  end
@@ -57,7 +57,7 @@ module Restforce
57
57
 
58
58
  def ensure_id
59
59
  return true if self.Id?
60
- raise 'You need to query the Id for the record first.'
60
+ raise ArgumentError, 'You need to query the Id for the record first.'
61
61
  end
62
62
 
63
63
  end
@@ -0,0 +1,13 @@
1
+ module Restforce
2
+ module Tooling
3
+ class Client < AbstractClient
4
+
5
+ private
6
+
7
+ def api_path(path)
8
+ super("tooling/#{path}")
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module Restforce
2
- VERSION = '1.3.0'
2
+ VERSION = '1.4.0'
3
3
  end
@@ -1,74 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- shared_examples_for 'methods' do
4
- describe '#new' do
5
- context 'without options passed in' do
6
- it 'does not raise an exception' do
7
- expect {
8
- described_class.new
9
- }.to_not raise_error
10
- end
11
- end
12
-
13
- context 'with a non-hash value' do
14
- it 'raises an exception' do
15
- expect {
16
- described_class.new 'foo'
17
- }.to raise_error, 'Please specify a hash of options'
18
- end
19
- end
20
- end
21
-
22
- describe '@options' do
23
- subject { client.instance_variable_get :@options }
24
-
25
- its([:oauth_token]) { should eq oauth_token }
26
- its([:refresh_token]) { should eq refresh_token }
27
- its([:client_id]) { should eq client_id }
28
- its([:client_secret]) { should eq client_secret }
29
- its([:username]) { should eq username }
30
- its([:password]) { should eq password }
31
- its([:security_token]) { should eq security_token }
32
- end
33
-
34
- describe '.instance_url' do
35
- subject { client.instance_url }
36
- it { should eq 'https://na1.salesforce.com' }
37
- end
38
-
39
- describe '.url' do
40
- subject { client.url(resource) }
41
-
42
- context 'when given something that responds to to_sparam' do
43
- let(:resource) { Struct.new(:to_sparam).new('1234') }
44
- it { should eq 'https://na1.salesforce.com/1234' }
45
- end
46
-
47
- context 'when given a string' do
48
- let(:resource) { '4321' }
49
- it { should eq 'https://na1.salesforce.com/4321' }
50
- end
51
- end
52
-
53
- describe '.authentication_middleware' do
54
- subject { client.send :authentication_middleware }
55
-
56
- context 'without required options for authentication middleware to be provided' do
57
- let(:client_options) { {} }
58
- it { should be_nil }
59
- end
60
-
61
- context 'with username, password, security token, client id and client secret provided' do
62
- let(:client_options) { password_options }
63
- it { should eq Restforce::Middleware::Authentication::Password }
64
- end
65
-
66
- context 'with refresh token, client id and client secret provided' do
67
- let(:client_options) { oauth_options }
68
- it { should eq Restforce::Middleware::Authentication::Token }
69
- end
70
- end
71
-
3
+ shared_examples_for Restforce::AbstractClient do
72
4
  describe '.list_sobjects' do
73
5
  requests :sobjects, :fixture => 'sobject/describe_sobjects_success_response'
74
6
 
@@ -145,15 +77,15 @@ shared_examples_for 'methods' do
145
77
  :status => 404,
146
78
  :fixture => 'sobject/delete_error_response'
147
79
 
148
- subject { client.update!('Account', :Id => '001D000000INjVe', :Name => 'Foobar') }
149
- specify { expect { subject }.to raise_error Faraday::Error::ResourceNotFound }
80
+ subject { lambda { client.update!('Account', :Id => '001D000000INjVe', :Name => 'Foobar') } }
81
+ it { should raise_error Faraday::Error::ResourceNotFound }
150
82
  end
151
83
  end
152
84
 
153
85
  describe '.update' do
154
86
  context 'with missing Id' do
155
- subject { client.update('Account', :Name => 'Foobar') }
156
- specify { expect { subject }.to raise_error RuntimeError, 'Id field missing.' }
87
+ subject { lambda { client.update('Account', :Name => 'Foobar') } }
88
+ it { should raise_error ArgumentError, 'Id field missing from attrs.' }
157
89
  end
158
90
 
159
91
  context 'with invalid Id' do
@@ -214,7 +146,7 @@ shared_examples_for 'methods' do
214
146
  end
215
147
 
216
148
  describe '.destroy!' do
217
- subject { client.destroy!('Account', '001D000000INjVe') }
149
+ subject(:destroy!) { client.destroy!('Account', '001D000000INjVe') }
218
150
 
219
151
  context 'with invalid Id' do
220
152
  requests 'sobjects/Account/001D000000INjVe',
@@ -222,7 +154,8 @@ shared_examples_for 'methods' do
222
154
  :method => :delete,
223
155
  :status => 404
224
156
 
225
- specify { expect { subject }.to raise_error Faraday::Error::ResourceNotFound }
157
+ subject { lambda { destroy! } }
158
+ it { should raise_error Faraday::Error::ResourceNotFound }
226
159
  end
227
160
 
228
161
  context 'with success' do
@@ -269,44 +202,8 @@ shared_examples_for 'methods' do
269
202
  end
270
203
  end
271
204
 
272
- describe '.picklist_values' do
273
- requests 'sobjects/Account/describe',
274
- :fixture => 'sobject/sobject_describe_success_response'
275
-
276
- context 'when given a picklist field' do
277
- subject { client.picklist_values('Account', 'Picklist_Field') }
278
- it { should be_an Array }
279
- its(:length) { should eq 3 }
280
- it { should include_picklist_values ['one', 'two', 'three'] }
281
- end
282
-
283
- context 'when given a multipicklist field' do
284
- subject { client.picklist_values('Account', 'Picklist_Multiselect_Field') }
285
- it { should be_an Array }
286
- its(:length) { should eq 3 }
287
- it { should include_picklist_values ['four', 'five', 'six'] }
288
- end
289
-
290
- describe 'dependent picklists' do
291
- context 'when given a picklist field that has a dependency' do
292
- subject { client.picklist_values('Account', 'Dependent_Picklist_Field', :valid_for => 'one') }
293
- it { should be_an Array }
294
- its(:length) { should eq 2 }
295
- it { should include_picklist_values ['seven', 'eight'] }
296
- it { should_not include_picklist_values ['nine'] }
297
- end
298
-
299
- context 'when given a picklist field that does not have a dependency' do
300
- subject { client.picklist_values('Account', 'Picklist_Field', :valid_for => 'one') }
301
- it 'raises an exception' do
302
- expect { subject }.to raise_error(/Picklist_Field is not a dependent picklist/)
303
- end
304
- end
305
- end
306
- end
307
-
308
205
  describe '.authenticate!' do
309
- subject { client.authenticate! }
206
+ subject(:authenticate!) { client.authenticate! }
310
207
 
311
208
  context 'when successful' do
312
209
  before do
@@ -327,29 +224,8 @@ shared_examples_for 'methods' do
327
224
  client.stub(:authentication_middleware).and_return(nil)
328
225
  end
329
226
 
330
- it 'should raise an exception' do
331
- expect { subject }.to raise_error Restforce::AuthenticationError, 'No authentication middleware present'
332
- end
333
- end
334
- end
335
-
336
- describe '.cache' do
337
- let(:cache) { double('cache') }
338
-
339
- subject { client.send :cache }
340
- it { should eq cache }
341
- end
342
-
343
- describe '.middleware' do
344
- subject { client.middleware }
345
- it { should eq client.send(:connection).builder }
346
-
347
- context 'adding middleware' do
348
- before do
349
- client.middleware.use FaradayMiddleware::Instrumentation
350
- end
351
-
352
- its(:handlers) { should include FaradayMiddleware::Instrumentation }
227
+ subject { lambda { authenticate! } }
228
+ it { should raise_error Restforce::AuthenticationError, 'No authentication middleware present'}
353
229
  end
354
230
  end
355
231
 
@@ -367,56 +243,6 @@ shared_examples_for 'methods' do
367
243
  it { should be_an Enumerable }
368
244
  end
369
245
 
370
- unless RUBY_PLATFORM == 'java'
371
- describe '.faye', :eventmachine => true do
372
- subject { client.faye }
373
-
374
- context 'with missing instance url' do
375
- let(:instance_url) { nil }
376
- specify { expect { subject }.to raise_error RuntimeError, 'Instance URL missing. Call .authenticate! first.' }
377
- end
378
-
379
- context 'with oauth token and instance url' do
380
- let(:instance_url) { 'http://google.com' }
381
- let(:oauth_token) { 'bar' }
382
- specify { expect { subject }.to_not raise_error }
383
- end
384
-
385
- context 'when the connection goes down' do
386
- it 'should reauthenticate' do
387
- access_token = double('access token')
388
- access_token.stub(:access_token).and_return('token')
389
- client.should_receive(:authenticate!).and_return(access_token)
390
- client.faye.should_receive(:set_header).with('Authorization', "OAuth token")
391
- client.faye.trigger('transport:down')
392
- end
393
- end
394
- end
395
-
396
- describe '.subcribe', :eventmachine => true do
397
- context 'when given a single pushtopic' do
398
- it 'subscribes to the pushtopic' do
399
- client.faye.should_receive(:subscribe).with(['/topic/PushTopic'])
400
- client.subscribe('PushTopic')
401
- end
402
- end
403
-
404
- context 'when given an array of pushtopics' do
405
- it 'subscribes to each pushtopic' do
406
- client.faye.should_receive(:subscribe).with(['/topic/PushTopic1', '/topic/PushTopic2'])
407
- client.subscribe(['PushTopic1', 'PushTopic2'])
408
- end
409
- end
410
- end
411
- end
412
-
413
- describe '.decode_signed_request' do
414
- it 'proxies to Restforce::SignedRequest' do
415
- Restforce::SignedRequest.should_receive(:decode).with('foo', client_secret)
416
- client.decode_signed_request('foo')
417
- end
418
- end
419
-
420
246
  describe 'authentication retries' do
421
247
  context 'when retries reaches 0' do
422
248
  before do
@@ -428,8 +254,8 @@ shared_examples_for 'methods' do
428
254
  to_return(:status => 200, :body => fixture(:auth_success_response))
429
255
  end
430
256
 
431
- subject { client.query('SELECT some, fields FROM object') }
432
- specify { expect { subject }.to raise_error Restforce::UnauthorizedError }
257
+ subject { lambda { client.query('SELECT some, fields FROM object') } }
258
+ it { should raise_error Restforce::UnauthorizedError }
433
259
  end
434
260
  end
435
261
 
@@ -457,43 +283,24 @@ shared_examples_for 'methods' do
457
283
  end
458
284
  end
459
285
 
460
- describe 'with mashify middleware' do
461
- describe Restforce::Client do
462
- include_context 'basic client'
463
- include_examples 'methods'
464
-
465
- describe '.mashify?' do
466
- subject { client.send :mashify? }
467
-
468
- it { should be_true }
469
- end
286
+ describe Restforce::AbstractClient do
287
+ describe 'with mashify' do
288
+ it_behaves_like Restforce::AbstractClient
470
289
 
471
290
  describe '.query' do
472
291
  context 'with pagination' do
292
+ subject { client.query('SELECT some, fields FROM object').next_page }
293
+
473
294
  requests 'query\?q', :fixture => 'sobject/query_paginated_first_page_response'
474
295
  requests 'query/01gD', :fixture => 'sobject/query_paginated_last_page_response'
475
296
 
476
- subject { client.query('SELECT some, fields FROM object').next_page }
477
297
  it { should be_a Restforce::Collection }
478
- specify { expect(subject.first.Text_Label).to eq 'Last Page' }
298
+ its('first.Text_Label') { should eq 'Last Page'}
479
299
  end
480
300
  end
481
301
  end
482
- end
483
-
484
- describe 'without mashify middleware' do
485
- before do
486
- client.middleware.delete(Restforce::Middleware::Mashify)
487
- end
488
-
489
- describe Restforce::Client do
490
- include_context 'basic client'
491
- include_examples 'methods'
492
-
493
- describe '.mashify?' do
494
- subject { client.send :mashify? }
495
302
 
496
- it { should be_false }
497
- end
303
+ describe 'without mashify', :mashify => false do
304
+ it_behaves_like Restforce::AbstractClient
498
305
  end
499
306
  end