hello_sign 1.1.0 → 1.1.1
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.
- data/lib/hello_sign.rb +29 -5
- data/lib/hello_sign/client.rb +13 -38
- data/lib/hello_sign/connection.rb +53 -0
- data/lib/hello_sign/error.rb +13 -9
- data/lib/hello_sign/middleware/parse_json.rb +22 -0
- data/lib/hello_sign/middleware/raise_error.rb +2 -0
- data/lib/hello_sign/parameters/reusable_form_signature_request.rb +27 -14
- data/lib/hello_sign/parameters/signature_request.rb +29 -21
- data/lib/hello_sign/parameters/unclaimed_draft.rb +8 -5
- data/lib/hello_sign/proxy/signature_request.rb +30 -18
- data/lib/hello_sign/version.rb +1 -1
- data/spec/helper.rb +0 -6
- data/spec/integration/hello_sign_spec.rb +7 -1
- data/spec/integration/helper.rb +17 -4
- data/spec/shared_examples/proxy.rb +58 -15
- data/spec/unit/client_spec.rb +42 -27
- data/spec/unit/connection_spec.rb +38 -0
- data/spec/unit/error_spec.rb +65 -13
- data/spec/unit/hello_sign_spec.rb +66 -23
- data/spec/unit/middleware/parse_json_spec.rb +38 -0
- data/spec/unit/middleware/raise_error_spec.rb +36 -23
- data/spec/unit/parameters/reusable_form_signature_request_spec.rb +74 -37
- data/spec/unit/parameters/signature_request_spec.rb +11 -5
- data/spec/unit/parameters/unclaimed_draft_spec.rb +14 -6
- data/spec/unit/proxy/account_spec.rb +17 -9
- data/spec/unit/proxy/reusable_form_spec.rb +31 -14
- data/spec/unit/proxy/settings_spec.rb +11 -4
- data/spec/unit/proxy/signature_request_spec.rb +74 -38
- data/spec/unit/proxy/team_spec.rb +39 -20
- data/spec/unit/proxy/unclaimed_draft_spec.rb +25 -6
- data/spec/unit/upload_io_spec.rb +69 -27
- metadata +20 -40
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'hello_sign/middleware/parse_json'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
describe HelloSign::Middleware::ParseJson do
|
6
|
+
let(:middleware) do
|
7
|
+
HelloSign::Middleware::ParseJson.new(->(env) { Faraday::Response.new(env) })
|
8
|
+
end
|
9
|
+
|
10
|
+
it "does not blow up if there is not a body" do
|
11
|
+
expect { middleware.call({}) }.not_to raise_error
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when the content type is application/json" do
|
15
|
+
let(:env) { {response_headers: {'Content-Type' => 'application/json'}} }
|
16
|
+
|
17
|
+
it "does not change a nil body" do
|
18
|
+
expect(middleware.call(env.merge(body: nil)).env[:body]).to eq nil
|
19
|
+
end
|
20
|
+
|
21
|
+
context "and the body is valid JSON" do
|
22
|
+
let(:body) { {first: 1, second: 2}.to_json }
|
23
|
+
|
24
|
+
it "parses the body into a hash with symbols as keys" do
|
25
|
+
expect(middleware.call(env.merge(body: body)).env[:body])
|
26
|
+
.to eq({first: 1, second: 2})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when the content type is not application/json" do
|
32
|
+
let(:env) { {response_headers: {'Content-Type' => 'application/pdf'}} }
|
33
|
+
|
34
|
+
it "does not parse the body" do
|
35
|
+
expect(middleware.call(env.merge(body: 'dave')).env[:body]).to eq 'dave'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -8,34 +8,46 @@ describe HelloSign::Middleware::RaiseError do
|
|
8
8
|
specify { expect { call_with_error(error) }.to raise_error exception }
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
context "when raising an exception" do
|
28
|
-
let(:expected_message) { "[Status code: 418] I'm a teapot." }
|
11
|
+
context "when the content type is application/json" do
|
12
|
+
{
|
13
|
+
'unauthorized' => HelloSign::Error::Unauthorized,
|
14
|
+
'forbidden' => HelloSign::Error::Forbidden,
|
15
|
+
'not_found' => HelloSign::Error::NotFound,
|
16
|
+
'unknown' => HelloSign::Error::Unknown,
|
17
|
+
'team_invite_failed' => HelloSign::Error::TeamInviteFailed,
|
18
|
+
'invalid_recipient' => HelloSign::Error::InvalidRecipient,
|
19
|
+
'convert_failed' => HelloSign::Error::ConvertFailed,
|
20
|
+
'signature_request_cancel_failed' => HelloSign::Error::SignatureRequestCancelFailed,
|
21
|
+
'unidentified_error' => HelloSign::Error
|
22
|
+
}.each { |error_pair| it_raises_the_proper_exception(*error_pair) }
|
23
|
+
|
24
|
+
it "does not blow up if there is not a body" do
|
25
|
+
expect { middleware.call({}) }.not_to raise_error
|
26
|
+
end
|
29
27
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
context "and an exception is raised" do
|
29
|
+
it "returns the proper message" do
|
30
|
+
begin
|
31
|
+
middleware.call(
|
32
|
+
call_with_error(
|
33
|
+
'bad_request',
|
34
|
+
message: "I'm a teapot.",
|
35
|
+
status_code: 418
|
36
|
+
).merge(response_headers)
|
37
|
+
)
|
38
|
+
rescue HelloSign::Error::BadRequest => e
|
39
|
+
expect("#{e}").to match /#{Regexp.escape("[Status code: 418] I'm a teapot")}/
|
40
|
+
end
|
35
41
|
end
|
36
42
|
end
|
37
43
|
end
|
38
44
|
|
45
|
+
context "when the body is not a hash" do
|
46
|
+
it "does not blow up" do
|
47
|
+
expect { middleware.call(body: 'hal') }.not_to raise_error
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
39
51
|
private
|
40
52
|
|
41
53
|
def call_with_error(error, options = {})
|
@@ -43,6 +55,7 @@ describe HelloSign::Middleware::RaiseError do
|
|
43
55
|
body: {error: {error_name: error, error_msg: options[:message]}},
|
44
56
|
response: {status: options[:status_code]}
|
45
57
|
}
|
58
|
+
|
46
59
|
middleware.call(env)
|
47
60
|
end
|
48
61
|
|
@@ -5,46 +5,83 @@ describe HelloSign::Parameters::ReusableFormSignatureRequest do
|
|
5
5
|
describe "#formatted" do
|
6
6
|
let(:request_parameters) { HelloSign::Parameters::ReusableFormSignatureRequest.new }
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
8
|
+
context "when all parameters are provided" do
|
9
|
+
let(:expected) do
|
10
|
+
{
|
11
|
+
reusable_form_id: 'form_id',
|
12
|
+
title: 'Lease',
|
13
|
+
subject: 'Sign this',
|
14
|
+
message: 'You must sign this.',
|
15
|
+
ccs: {
|
16
|
+
'lawyer' => {email_address: 'lawyer@lawfirm.com'},
|
17
|
+
'accountant' => {email_address: 'accountant@llc.com'}
|
18
|
+
},
|
19
|
+
signers: {
|
20
|
+
'consultant' => {name: 'Jack', email_address: 'jack@hill.com'},
|
21
|
+
'client' => {name: 'Jill', email_address: 'jill@hill.com'}
|
22
|
+
},
|
23
|
+
custom_fields: {
|
24
|
+
'cost' => '$20,000',
|
25
|
+
'time' => 'two weeks'
|
26
|
+
}
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
before do
|
31
|
+
request_parameters.reusable_form_id = 'form_id'
|
32
|
+
request_parameters.title = 'Lease'
|
33
|
+
request_parameters.subject = 'Sign this'
|
34
|
+
request_parameters.message = 'You must sign this.'
|
35
|
+
request_parameters.ccs = [
|
36
|
+
{email_address: 'lawyer@lawfirm.com', role: 'lawyer'},
|
37
|
+
{email_address: 'accountant@llc.com', role: 'accountant'}
|
38
|
+
]
|
39
|
+
request_parameters.signers = [
|
40
|
+
{name: 'Jack', email_address: 'jack@hill.com', role: 'consultant'},
|
41
|
+
{name: 'Jill', email_address: 'jill@hill.com', role: 'client'}
|
42
|
+
]
|
43
|
+
request_parameters.custom_fields = [
|
44
|
+
{name: 'cost', value: '$20,000'},
|
45
|
+
{name: 'time', value: 'two weeks'}
|
46
|
+
]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns formatted parameters" do
|
50
|
+
expect(request_parameters.formatted).to eq expected
|
51
|
+
end
|
25
52
|
end
|
26
53
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
custom_fields
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
54
|
+
context "when the ccs parameter is not provided" do
|
55
|
+
before do
|
56
|
+
request_parameters.signers = []
|
57
|
+
request_parameters.custom_fields = []
|
58
|
+
end
|
59
|
+
|
60
|
+
it "defaults to an empty hash" do
|
61
|
+
expect(request_parameters.formatted[:ccs]).to eq({})
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when the signers parameter is not provided" do
|
66
|
+
before do
|
67
|
+
request_parameters.ccs = []
|
68
|
+
request_parameters.custom_fields = []
|
69
|
+
end
|
70
|
+
|
71
|
+
it "defaults to an empty hash" do
|
72
|
+
expect(request_parameters.formatted[:custom_fields]).to eq({})
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "when the custom_fields parameter is not provided" do
|
77
|
+
before do
|
78
|
+
request_parameters.ccs = []
|
79
|
+
request_parameters.signers = []
|
80
|
+
end
|
46
81
|
|
47
|
-
|
82
|
+
it "defaults to an empty hash" do
|
83
|
+
expect(request_parameters.formatted[:custom_fields]).to eq({})
|
84
|
+
end
|
48
85
|
end
|
49
86
|
end
|
50
87
|
end
|
@@ -15,7 +15,7 @@ describe HelloSign::Parameters::SignatureRequest do
|
|
15
15
|
message: 'You must sign this.',
|
16
16
|
cc_email_addresses: ['lawyer@lawfirm.com', 'spouse@family.com'],
|
17
17
|
signers: {
|
18
|
-
0 => {name: 'Jack', email_address: 'jack@hill.com', order: 0},
|
18
|
+
0 => {name: 'Jack', email_address: 'jack@hill.com', order: 0},
|
19
19
|
1 => {name: 'Jill', email_address: 'jill@hill.com', order: 1}
|
20
20
|
},
|
21
21
|
file: {1 => text_file, 2 => image_file}
|
@@ -35,13 +35,19 @@ describe HelloSign::Parameters::SignatureRequest do
|
|
35
35
|
@file_data_1 = {filename: 'test.txt', io: 'text file IO object', mime: 'text/plain'},
|
36
36
|
@file_data_2 = {filename: 'test.jpg', io: 'image file IO object', mime: 'image/jpeg'}
|
37
37
|
]
|
38
|
+
|
39
|
+
allow(HelloSign::File).to(
|
40
|
+
receive(:new).with(@file_data_1).and_return(text_file)
|
41
|
+
)
|
42
|
+
allow(HelloSign::File).to(
|
43
|
+
receive(:new).with(@file_data_2).and_return(image_file)
|
44
|
+
)
|
45
|
+
[text_file, image_file].each do |file|
|
46
|
+
allow(file).to receive(:attachment).and_return(file)
|
47
|
+
end
|
38
48
|
end
|
39
49
|
|
40
50
|
it "returns formatted parameters" do
|
41
|
-
HelloSign::File.should_receive(:new).with(@file_data_1).and_return(text_file)
|
42
|
-
HelloSign::File.should_receive(:new).with(@file_data_2).and_return(image_file)
|
43
|
-
[text_file, image_file].each { |file| file.should_receive(:attachment).and_return(file) }
|
44
|
-
|
45
51
|
expect(request_parameters.formatted).to eq expected
|
46
52
|
end
|
47
53
|
end
|
@@ -12,17 +12,25 @@ describe HelloSign::Parameters::UnclaimedDraft do
|
|
12
12
|
|
13
13
|
before do
|
14
14
|
draft_parameters.files = [
|
15
|
-
@file_data_1 = {filename: 'test.txt', io: text_file,
|
15
|
+
@file_data_1 = {filename: 'test.txt', io: text_file, mime: 'text/html'},
|
16
16
|
@file_data_2 = {filename: 'test.jpg', io: image, mime: 'image/jpeg'}
|
17
17
|
]
|
18
|
+
|
19
|
+
allow(HelloSign::File).to(
|
20
|
+
receive(:new).with(@file_data_1).and_return(text_file)
|
21
|
+
)
|
22
|
+
allow(HelloSign::File).to(
|
23
|
+
receive(:new).with(@file_data_2).and_return(image)
|
24
|
+
)
|
25
|
+
[text_file, image].each do |file|
|
26
|
+
allow(file).to receive(:attachment).and_return(file)
|
27
|
+
end
|
18
28
|
end
|
19
29
|
|
20
30
|
it "returns formatted parameters" do
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
expect(draft_parameters.formatted).to eq({file: {0 => text_file, 1 => image}})
|
31
|
+
expect(draft_parameters.formatted).to(
|
32
|
+
eq({file: {0 => text_file, 1 => image}})
|
33
|
+
)
|
26
34
|
end
|
27
35
|
end
|
28
36
|
end
|
@@ -10,18 +10,21 @@ describe HelloSign::Proxy::Account do
|
|
10
10
|
let(:email_address) { 'david@bowman.com' }
|
11
11
|
let(:password) { 'password' }
|
12
12
|
|
13
|
-
before
|
13
|
+
before do
|
14
|
+
allow(client).to receive(:post).and_return(api_response)
|
15
|
+
|
16
|
+
account_proxy.create(
|
17
|
+
email_address: 'david@bowman.com',
|
18
|
+
password: 'space'
|
19
|
+
)
|
20
|
+
end
|
14
21
|
|
15
22
|
it "sends a request to create an account" do
|
16
|
-
client.
|
23
|
+
expect(client).to have_received(:post).with(
|
17
24
|
'/account/create',
|
18
25
|
body: {email_address: 'david@bowman.com', password: 'space'},
|
19
26
|
auth_not_required: true
|
20
27
|
)
|
21
|
-
account_proxy.create(
|
22
|
-
email_address: 'david@bowman.com',
|
23
|
-
password: 'space'
|
24
|
-
)
|
25
28
|
end
|
26
29
|
|
27
30
|
it "returns the API response" do
|
@@ -30,15 +33,20 @@ describe HelloSign::Proxy::Account do
|
|
30
33
|
email_address: 'david@bowman.com',
|
31
34
|
password: 'space'
|
32
35
|
)
|
33
|
-
).
|
36
|
+
).to eq api_response
|
34
37
|
end
|
35
38
|
end
|
36
39
|
|
37
40
|
describe "#settings" do
|
38
|
-
let(:settings_proxy)
|
41
|
+
let(:settings_proxy) { double('settings proxy') }
|
42
|
+
|
43
|
+
before do
|
44
|
+
allow(HelloSign::Proxy::Settings).to(
|
45
|
+
receive(:new).with(client).and_return(settings_proxy)
|
46
|
+
)
|
47
|
+
end
|
39
48
|
|
40
49
|
it "returns a signature request proxy" do
|
41
|
-
HelloSign::Proxy::Settings.should_receive(:new).with(client).and_return(settings_proxy)
|
42
50
|
expect(account_proxy.settings).to be settings_proxy
|
43
51
|
end
|
44
52
|
end
|
@@ -6,54 +6,71 @@ describe HelloSign::Proxy::ReusableForm do
|
|
6
6
|
let(:api_response) { double('API response') }
|
7
7
|
let(:form_id) { 'form_id' }
|
8
8
|
let(:email_address) { 'bob@example.com' }
|
9
|
+
|
9
10
|
subject(:rf_proxy) { HelloSign::Proxy::ReusableForm.new(client, form_id) }
|
10
11
|
|
11
12
|
before do
|
12
|
-
client.
|
13
|
-
client.
|
13
|
+
allow(client).to receive(:get).and_return(api_response)
|
14
|
+
allow(client).to receive(:post).and_return(api_response)
|
14
15
|
end
|
15
16
|
|
16
17
|
describe "#list" do
|
18
|
+
before { @response = rf_proxy.list(page: 10) }
|
19
|
+
|
17
20
|
it "sends a request to fetch the list of reusable forms" do
|
18
|
-
client
|
19
|
-
|
21
|
+
expect(client).to(
|
22
|
+
have_received(:get).with('/reusable_form/list', params: {page: 10})
|
23
|
+
)
|
20
24
|
end
|
21
25
|
|
22
26
|
it "returns the API response" do
|
23
|
-
expect(
|
27
|
+
expect(@response).to eq api_response
|
24
28
|
end
|
25
29
|
end
|
26
30
|
|
27
31
|
describe "#show" do
|
32
|
+
before { @response = rf_proxy.show }
|
33
|
+
|
28
34
|
it "sends a request to fetch the details of a reusable form" do
|
29
|
-
client.
|
30
|
-
rf_proxy.show
|
35
|
+
expect(client).to have_received(:get).with("/reusable_form/#{form_id}")
|
31
36
|
end
|
32
37
|
|
33
38
|
it "returns the API response" do
|
34
|
-
expect(
|
39
|
+
expect(@response).to eq api_response
|
35
40
|
end
|
36
41
|
end
|
37
42
|
|
38
43
|
describe "#grant_access" do
|
44
|
+
before { @response = rf_proxy.grant_access(email_address: email_address) }
|
45
|
+
|
39
46
|
it "sends a request to grant access" do
|
40
|
-
client
|
41
|
-
|
47
|
+
expect(client).to(
|
48
|
+
have_received(:post).with(
|
49
|
+
"/reusable_form/add_user/#{form_id}",
|
50
|
+
body: {email_address: email_address}
|
51
|
+
)
|
52
|
+
)
|
42
53
|
end
|
43
54
|
|
44
55
|
it "returns the API response" do
|
45
|
-
expect(
|
56
|
+
expect(@response).to eq api_response
|
46
57
|
end
|
47
58
|
end
|
48
59
|
|
49
60
|
describe "#revoke_access" do
|
61
|
+
before { @response = rf_proxy.revoke_access(email_address: email_address) }
|
62
|
+
|
50
63
|
it "sends a request to revoke access" do
|
51
|
-
client
|
52
|
-
|
64
|
+
expect(client).to(
|
65
|
+
have_received(:post).with(
|
66
|
+
"/reusable_form/remove_user/#{form_id}",
|
67
|
+
body: {email_address: email_address}
|
68
|
+
)
|
69
|
+
)
|
53
70
|
end
|
54
71
|
|
55
72
|
it "returns the API response" do
|
56
|
-
expect(
|
73
|
+
expect(@response).to eq api_response
|
57
74
|
end
|
58
75
|
end
|
59
76
|
end
|
@@ -3,6 +3,7 @@ require 'hello_sign/proxy/settings'
|
|
3
3
|
|
4
4
|
describe HelloSign::Proxy::Settings do
|
5
5
|
let(:client) { double('client') }
|
6
|
+
|
6
7
|
subject(:settings) { HelloSign::Proxy::Settings.new(client) }
|
7
8
|
|
8
9
|
describe "#client" do
|
@@ -15,15 +16,21 @@ describe HelloSign::Proxy::Settings do
|
|
15
16
|
let(:callback_url) { 'http://www.callmemaybe.com' }
|
16
17
|
let(:api_response) { double('API response') }
|
17
18
|
|
18
|
-
before
|
19
|
+
before do
|
20
|
+
allow(client).to receive(:post).and_return(api_response)
|
21
|
+
|
22
|
+
@response = settings.update(callback_url: callback_url)
|
23
|
+
end
|
19
24
|
|
20
25
|
it "sends a request to update the account's settings" do
|
21
|
-
client.
|
22
|
-
|
26
|
+
expect(client).to have_received(:post).with(
|
27
|
+
'/account',
|
28
|
+
body: {callback_url: callback_url}
|
29
|
+
)
|
23
30
|
end
|
24
31
|
|
25
32
|
it "returns the API response" do
|
26
|
-
expect(
|
33
|
+
expect(@response).to be api_response
|
27
34
|
end
|
28
35
|
end
|
29
36
|
end
|