rdstation-ruby-client 2.1.0 → 2.5.0
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 +5 -5
- data/CHANGELOG.md +121 -1
- data/README.md +106 -22
- data/Rakefile +4 -0
- data/lib/rdstation-ruby-client.rb +6 -1
- data/lib/rdstation.rb +19 -0
- data/lib/rdstation/api_response.rb +1 -2
- data/lib/rdstation/authentication.rb +8 -3
- data/lib/rdstation/{authorization_header.rb → authorization.rb} +11 -8
- data/lib/rdstation/builder/field.rb +70 -0
- data/lib/rdstation/client.rb +17 -7
- data/lib/rdstation/contacts.rb +22 -13
- data/lib/rdstation/error.rb +3 -0
- data/lib/rdstation/error/format.rb +29 -3
- data/lib/rdstation/error/formatter.rb +69 -8
- data/lib/rdstation/error_handler.rb +6 -1
- data/lib/rdstation/error_handler/invalid_refresh_token.rb +24 -0
- data/lib/rdstation/error_handler/unauthorized.rb +2 -0
- data/lib/rdstation/events.rb +7 -12
- data/lib/rdstation/fields.rb +35 -6
- data/lib/rdstation/retryable_request.rb +35 -0
- data/lib/rdstation/version.rb +1 -1
- data/lib/rdstation/webhooks.rb +25 -13
- data/rdstation-ruby-client.gemspec +2 -1
- data/spec/lib/rdstation/api_response_spec.rb +34 -0
- data/spec/lib/rdstation/authentication_spec.rb +105 -2
- data/spec/lib/rdstation/{authorization_header_spec.rb → authorization_spec.rb} +3 -3
- data/spec/lib/rdstation/builder/field_spec.rb +69 -0
- data/spec/lib/rdstation/client_spec.rb +6 -6
- data/spec/lib/rdstation/contacts_spec.rb +23 -3
- data/spec/lib/rdstation/error/format_spec.rb +63 -0
- data/spec/lib/rdstation/error/formatter_spec.rb +113 -0
- data/spec/lib/rdstation/error_handler/invalid_refresh_token_spec.rb +53 -0
- data/spec/lib/rdstation/error_handler_spec.rb +23 -0
- data/spec/lib/rdstation/events_spec.rb +8 -3
- data/spec/lib/rdstation/fields_spec.rb +6 -1
- data/spec/lib/rdstation/retryable_request_spec.rb +142 -0
- data/spec/lib/rdstation/webhooks_spec.rb +26 -1
- data/spec/lib/rdstation_spec.rb +18 -0
- metadata +36 -8
@@ -0,0 +1,24 @@
|
|
1
|
+
module RDStation
|
2
|
+
class ErrorHandler
|
3
|
+
class InvalidRefreshToken
|
4
|
+
attr_reader :errors
|
5
|
+
|
6
|
+
ERROR_CODE = 'INVALID_REFRESH_TOKEN'.freeze
|
7
|
+
|
8
|
+
def initialize(errors)
|
9
|
+
@errors = errors
|
10
|
+
end
|
11
|
+
|
12
|
+
def raise_error
|
13
|
+
return if invalid_refresh_token_error.empty?
|
14
|
+
raise RDStation::Error::InvalidRefreshToken, invalid_refresh_token_error
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def invalid_refresh_token_error
|
20
|
+
errors.find { |error| error['error_type'] == ERROR_CODE }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative 'expired_access_token'
|
2
2
|
require_relative 'expired_code_grant'
|
3
3
|
require_relative 'invalid_credentials'
|
4
|
+
require_relative 'invalid_refresh_token'
|
4
5
|
|
5
6
|
module RDStation
|
6
7
|
class ErrorHandler
|
@@ -9,6 +10,7 @@ module RDStation
|
|
9
10
|
ErrorHandler::ExpiredAccessToken,
|
10
11
|
ErrorHandler::ExpiredCodeGrant,
|
11
12
|
ErrorHandler::InvalidCredentials,
|
13
|
+
ErrorHandler::InvalidRefreshToken,
|
12
14
|
].freeze
|
13
15
|
|
14
16
|
def initialize(array_of_errors)
|
data/lib/rdstation/events.rb
CHANGED
@@ -1,24 +1,19 @@
|
|
1
1
|
module RDStation
|
2
2
|
class Events
|
3
3
|
include HTTParty
|
4
|
+
include ::RDStation::RetryableRequest
|
4
5
|
|
5
6
|
EVENTS_ENDPOINT = 'https://api.rd.services/platform/events'.freeze
|
6
7
|
|
7
|
-
def initialize(
|
8
|
-
@
|
8
|
+
def initialize(authorization:)
|
9
|
+
@authorization = authorization
|
9
10
|
end
|
10
11
|
|
11
12
|
def create(payload)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def errors?(response_body)
|
21
|
-
response_body.is_a?(Array) || response_body['errors']
|
13
|
+
retryable_request(@authorization) do |authorization|
|
14
|
+
response = self.class.post(EVENTS_ENDPOINT, headers: authorization.headers, body: payload.to_json)
|
15
|
+
ApiResponse.build(response)
|
16
|
+
end
|
22
17
|
end
|
23
18
|
end
|
24
19
|
end
|
data/lib/rdstation/fields.rb
CHANGED
@@ -1,19 +1,48 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module RDStation
|
3
|
-
# More info: https://developers.rdstation.com/pt-BR/reference/
|
3
|
+
# More info: https://developers.rdstation.com/pt-BR/reference/fields
|
4
4
|
class Fields
|
5
5
|
include HTTParty
|
6
|
+
include ::RDStation::RetryableRequest
|
6
7
|
|
7
8
|
BASE_URL = 'https://api.rd.services/platform/contacts/fields'.freeze
|
8
|
-
|
9
|
-
def initialize(
|
10
|
-
@
|
9
|
+
|
10
|
+
def initialize(authorization:)
|
11
|
+
@authorization = authorization
|
11
12
|
end
|
12
13
|
|
13
14
|
def all
|
14
|
-
|
15
|
-
|
15
|
+
retryable_request(@authorization) do |authorization|
|
16
|
+
response = self.class.get(BASE_URL, headers: authorization.headers)
|
17
|
+
ApiResponse.build(response)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def create(payload)
|
22
|
+
retryable_request(@authorization) do |authorization|
|
23
|
+
response = self.class.post(BASE_URL, headers: authorization.headers, body: payload.to_json)
|
24
|
+
ApiResponse.build(response)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def update(uuid, payload)
|
29
|
+
retryable_request(@authorization) do |authorization|
|
30
|
+
response = self.class.patch(base_url(uuid), headers: authorization.headers, body: payload.to_json)
|
31
|
+
ApiResponse.build(response)
|
32
|
+
end
|
16
33
|
end
|
17
34
|
|
35
|
+
def delete(uuid)
|
36
|
+
retryable_request(@authorization) do |authorization|
|
37
|
+
response = self.class.delete(base_url(uuid), headers: authorization.headers)
|
38
|
+
ApiResponse.build(response)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def base_url(path = '')
|
45
|
+
"#{BASE_URL}/#{path}"
|
46
|
+
end
|
18
47
|
end
|
19
48
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RDStation
|
4
|
+
module RetryableRequest
|
5
|
+
MAX_RETRIES = 1
|
6
|
+
def retryable_request(authorization)
|
7
|
+
retries = 0
|
8
|
+
begin
|
9
|
+
yield authorization
|
10
|
+
rescue ::RDStation::Error::ExpiredAccessToken => e
|
11
|
+
raise if !retry_possible?(authorization) || retries >= MAX_RETRIES
|
12
|
+
|
13
|
+
retries += 1
|
14
|
+
refresh_access_token(authorization)
|
15
|
+
retry
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def retry_possible?(authorization)
|
20
|
+
[
|
21
|
+
RDStation.configuration&.client_id,
|
22
|
+
RDStation.configuration&.client_secret,
|
23
|
+
authorization.refresh_token
|
24
|
+
].all?
|
25
|
+
end
|
26
|
+
|
27
|
+
def refresh_access_token(authorization)
|
28
|
+
client = RDStation::Authentication.new
|
29
|
+
response = client.update_access_token(authorization.refresh_token)
|
30
|
+
authorization.access_token = response['access_token']
|
31
|
+
authorization.access_token_expires_in = response['expires_in']
|
32
|
+
RDStation.configuration&.access_token_refresh_callback&.call(authorization)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/rdstation/version.rb
CHANGED
data/lib/rdstation/webhooks.rb
CHANGED
@@ -1,35 +1,47 @@
|
|
1
1
|
module RDStation
|
2
2
|
class Webhooks
|
3
3
|
include HTTParty
|
4
|
+
include ::RDStation::RetryableRequest
|
4
5
|
|
5
|
-
def initialize(
|
6
|
-
@
|
6
|
+
def initialize(authorization:)
|
7
|
+
@authorization = authorization
|
7
8
|
end
|
8
9
|
|
9
10
|
def all
|
10
|
-
|
11
|
-
|
11
|
+
retryable_request(@authorization) do |authorization|
|
12
|
+
response = self.class.get(base_url, headers: authorization.headers)
|
13
|
+
ApiResponse.build(response)
|
14
|
+
end
|
12
15
|
end
|
13
16
|
|
14
17
|
def by_uuid(uuid)
|
15
|
-
|
16
|
-
|
18
|
+
retryable_request(@authorization) do |authorization|
|
19
|
+
response = self.class.get(base_url(uuid), headers: authorization.headers)
|
20
|
+
ApiResponse.build(response)
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
def create(payload)
|
20
|
-
|
21
|
-
|
25
|
+
retryable_request(@authorization) do |authorization|
|
26
|
+
response = self.class.post(base_url, headers: authorization.headers, body: payload.to_json)
|
27
|
+
ApiResponse.build(response)
|
28
|
+
end
|
22
29
|
end
|
23
30
|
|
24
31
|
def update(uuid, payload)
|
25
|
-
|
26
|
-
|
32
|
+
retryable_request(@authorization) do |authorization|
|
33
|
+
response = self.class.put(base_url(uuid), headers: authorization.headers, body: payload.to_json)
|
34
|
+
ApiResponse.build(response)
|
35
|
+
end
|
27
36
|
end
|
28
37
|
|
29
38
|
def delete(uuid)
|
30
|
-
|
31
|
-
|
32
|
-
|
39
|
+
retryable_request(@authorization) do |authorization|
|
40
|
+
response = self.class.delete(base_url(uuid), headers: authorization.headers)
|
41
|
+
return webhook_deleted_message unless response.body
|
42
|
+
|
43
|
+
RDStation::ErrorHandler.new(response).raise_error
|
44
|
+
end
|
33
45
|
end
|
34
46
|
|
35
47
|
private
|
@@ -20,12 +20,13 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.required_ruby_version = '>= 2.0.0'
|
22
22
|
|
23
|
-
spec.add_development_dependency "bundler", "
|
23
|
+
spec.add_development_dependency "bundler", "> 1.3"
|
24
24
|
spec.add_development_dependency "rake"
|
25
25
|
spec.add_development_dependency 'rspec'
|
26
26
|
spec.add_development_dependency 'webmock', '~> 2.1'
|
27
27
|
spec.add_development_dependency 'turn'
|
28
28
|
spec.add_development_dependency 'rspec_junit_formatter'
|
29
|
+
spec.add_development_dependency 'pry'
|
29
30
|
|
30
31
|
spec.add_dependency "httparty", "~> 0.12"
|
31
32
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe RDStation::ApiResponse do
|
4
|
+
describe ".build" do
|
5
|
+
context "when the response HTTP status is 2xx" do
|
6
|
+
let(:response) { OpenStruct.new(code: 200, body: '{}') }
|
7
|
+
|
8
|
+
it "returns the response body" do
|
9
|
+
expect(RDStation::ApiResponse.build(response)).to eq({})
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
shared_examples_for 'call_error_handler' do
|
14
|
+
it "calls error handler" do
|
15
|
+
error_handler = instance_double(RDStation::ErrorHandler)
|
16
|
+
allow(error_handler).to receive(:raise_error)
|
17
|
+
expect(RDStation::ErrorHandler).to receive(:new).with(response).and_return(error_handler)
|
18
|
+
RDStation::ApiResponse.build(response)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when the response is not in the 2xx range" do
|
23
|
+
let(:response) { OpenStruct.new(code: 404, body: '{}') }
|
24
|
+
|
25
|
+
it_behaves_like 'call_error_handler'
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when the response body is not JSON-parseable" do
|
29
|
+
let(:response) { OpenStruct.new(code: 504, body: '<html><head></head><body></body></html>') }
|
30
|
+
|
31
|
+
it_behaves_like 'call_error_handler'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -88,6 +88,34 @@ RSpec.describe RDStation::Authentication do
|
|
88
88
|
|
89
89
|
let(:authentication) { described_class.new('client_id', 'client_secret') }
|
90
90
|
|
91
|
+
describe '#auth_url' do
|
92
|
+
let(:configuration_client_id) { 'configuration_client_id' }
|
93
|
+
let(:configuration_client_secret) { 'configuration_client_secret' }
|
94
|
+
let(:redirect_url) { 'redirect_url' }
|
95
|
+
before do
|
96
|
+
RDStation.configure do |config|
|
97
|
+
config.client_id = configuration_client_id
|
98
|
+
config.client_secret = configuration_client_secret
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when client_id and client_secret are specified in initialization' do
|
103
|
+
it 'uses those specified in initialization' do
|
104
|
+
auth = described_class.new('initialization_client_id', 'initialization_client_secret')
|
105
|
+
expected = "https://api.rd.services/auth/dialog?client_id=initialization_client_id&redirect_url=#{redirect_url}"
|
106
|
+
expect(auth.auth_url(redirect_url)).to eq expected
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'when client_id and client_secret are specified only in configuration' do
|
111
|
+
it 'uses those specified in configuration' do
|
112
|
+
auth = described_class.new
|
113
|
+
expected = "https://api.rd.services/auth/dialog?client_id=#{configuration_client_id}&redirect_url=#{redirect_url}"
|
114
|
+
expect(auth.auth_url(redirect_url)).to eq expected
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
91
119
|
describe '#authenticate' do
|
92
120
|
context 'when the code is valid' do
|
93
121
|
before do
|
@@ -138,6 +166,37 @@ RSpec.describe RDStation::Authentication do
|
|
138
166
|
end.to raise_error(RDStation::Error::ExpiredCodeGrant)
|
139
167
|
end
|
140
168
|
end
|
169
|
+
|
170
|
+
context 'when client_id and client_secret are specified only in configuration' do
|
171
|
+
let(:authentication) { described_class.new }
|
172
|
+
let(:configuration_client_id) { 'configuration_client_id' }
|
173
|
+
let(:configuration_client_secret) { 'configuration_client_secret' }
|
174
|
+
let(:token_request_with_valid_code_secrets_from_config) do
|
175
|
+
{
|
176
|
+
client_id: configuration_client_id,
|
177
|
+
client_secret: configuration_client_secret,
|
178
|
+
code: 'valid_code'
|
179
|
+
}
|
180
|
+
end
|
181
|
+
before do
|
182
|
+
RDStation.configure do |config|
|
183
|
+
config.client_id = configuration_client_id
|
184
|
+
config.client_secret = configuration_client_secret
|
185
|
+
end
|
186
|
+
|
187
|
+
stub_request(:post, token_endpoint)
|
188
|
+
.with(
|
189
|
+
headers: request_headers,
|
190
|
+
body: token_request_with_valid_code_secrets_from_config.to_json
|
191
|
+
)
|
192
|
+
.to_return(credentials_response)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'returns the credentials' do
|
196
|
+
credentials_request = authentication.authenticate('valid_code')
|
197
|
+
expect(credentials_request).to eq(credentials)
|
198
|
+
end
|
199
|
+
end
|
141
200
|
end
|
142
201
|
|
143
202
|
describe '#update_access_token' do
|
@@ -158,19 +217,63 @@ RSpec.describe RDStation::Authentication do
|
|
158
217
|
end
|
159
218
|
|
160
219
|
context 'when the refresh token is invalid' do
|
220
|
+
let(:invalid_refresh_token_response) do
|
221
|
+
{
|
222
|
+
status: 401,
|
223
|
+
headers: { 'Content-Type' => 'application/json' },
|
224
|
+
body: {
|
225
|
+
errors: {
|
226
|
+
error_type: 'INVALID_REFRESH_TOKEN',
|
227
|
+
error_message: 'The provided refresh token is invalid or was revoked.'
|
228
|
+
}
|
229
|
+
}.to_json
|
230
|
+
}
|
231
|
+
end
|
232
|
+
|
161
233
|
before do
|
162
234
|
stub_request(:post, token_endpoint)
|
163
235
|
.with(
|
164
236
|
headers: request_headers,
|
165
237
|
body: token_request_with_invalid_refresh_token.to_json
|
166
238
|
)
|
167
|
-
.to_return(
|
239
|
+
.to_return(invalid_refresh_token_response)
|
168
240
|
end
|
169
241
|
|
170
242
|
it 'returns an auth error' do
|
171
243
|
expect do
|
172
244
|
authentication.update_access_token('invalid_refresh_token')
|
173
|
-
end.to raise_error(RDStation::Error::
|
245
|
+
end.to raise_error(RDStation::Error::InvalidRefreshToken)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
context 'when client_id and client_secret are specified only in configuration' do
|
250
|
+
let(:authentication) { described_class.new }
|
251
|
+
let(:configuration_client_id) { 'configuration_client_id' }
|
252
|
+
let(:configuration_client_secret) { 'configuration_client_secret' }
|
253
|
+
let(:token_request_with_valid_refresh_code_secrets_from_config) do
|
254
|
+
{
|
255
|
+
client_id: configuration_client_id,
|
256
|
+
client_secret: configuration_client_secret,
|
257
|
+
refresh_token: 'valid_refresh_token'
|
258
|
+
}
|
259
|
+
end
|
260
|
+
before do
|
261
|
+
RDStation.configure do |config|
|
262
|
+
config.client_id = configuration_client_id
|
263
|
+
config.client_secret = configuration_client_secret
|
264
|
+
end
|
265
|
+
|
266
|
+
stub_request(:post, token_endpoint)
|
267
|
+
.with(
|
268
|
+
headers: request_headers,
|
269
|
+
body: token_request_with_valid_refresh_code_secrets_from_config.to_json
|
270
|
+
)
|
271
|
+
.to_return(credentials_response)
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'returns the credentials' do
|
275
|
+
credentials_request = authentication.update_access_token('valid_refresh_token')
|
276
|
+
expect(credentials_request).to eq(credentials)
|
174
277
|
end
|
175
278
|
end
|
176
279
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
RSpec.describe RDStation::
|
3
|
+
RSpec.describe RDStation::Authorization do
|
4
4
|
|
5
5
|
describe ".initialize" do
|
6
6
|
context "when access_token is nil" do
|
@@ -12,11 +12,11 @@ RSpec.describe RDStation::AuthorizationHeader do
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
describe "#
|
15
|
+
describe "#headers" do
|
16
16
|
let(:access_token) { 'access_token' }
|
17
17
|
|
18
18
|
it "generates the correct header" do
|
19
|
-
header = described_class.new(access_token: access_token).
|
19
|
+
header = described_class.new(access_token: access_token).headers
|
20
20
|
expect(header['Authorization']).to eq "Bearer #{access_token}"
|
21
21
|
expect(header['Content-Type']).to eq "application/json"
|
22
22
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe RDStation::Builder::Field do
|
6
|
+
def valid_builder
|
7
|
+
described_class.new('cf_identifier')
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'when create a builder' do
|
11
|
+
context 'valid' do
|
12
|
+
let(:initial_parameters) do
|
13
|
+
'cf_api_identifier'
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:builder) { described_class.new(initial_parameters) }
|
17
|
+
|
18
|
+
let(:expected_result) do
|
19
|
+
{
|
20
|
+
'api_identifier' => 'cf_api_identifier',
|
21
|
+
'data_type' => 'STRING',
|
22
|
+
'presentation_type' => 'TEXT_INPUT',
|
23
|
+
'label' => { 'pt-BR' => 'My label' },
|
24
|
+
'name' => { 'pt-BR' => 'My name' }
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns an hash of required values' do
|
29
|
+
builder.label 'pt-BR', 'My label'
|
30
|
+
builder.name 'pt-BR', 'My name'
|
31
|
+
builder.data_type 'STRING'
|
32
|
+
builder.presentation_type 'TEXT_INPUT'
|
33
|
+
|
34
|
+
result = builder.build
|
35
|
+
expect(result).to eq(expected_result)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'invalid' do
|
40
|
+
it 'using invalid api_identifier ' do
|
41
|
+
expect { described_class.new('invald_identifier') }.to raise_error(
|
42
|
+
'api_identifier is not in a valid format, need start with "cf_"'
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'using invalid data_type ' do
|
47
|
+
expect { valid_builder.data_type('invalid_data_type') }.to raise_error(
|
48
|
+
'Not valid data_type - ["STRING", "INTEGER", "BOOLEAN", "STRING[]"]'
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'using invalid presentation_type ' do
|
53
|
+
expect { valid_builder.presentation_type('invalid presentation_type') }.to raise_error(
|
54
|
+
'Not valid presentation_type - ["TEXT_INPUT", "TEXT_AREA", "URL_INPUT", "PHONE_INPUT", "EMAIL_INPUT", "CHECK_BOX", "NUMBER_INPUT", "COMBO_BOX", "RADIO_BUTTON", "MULTIPLE_CHOICE"]'
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'without api_identifier' do
|
59
|
+
expect { described_class.new(nil) }.to raise_error('api_identifier required')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'without required fields' do
|
63
|
+
expect { valid_builder.build }.to raise_error(
|
64
|
+
'Required fields are missing - ["data_type", "presentation_type", "label", "name"]'
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|