acts_as_icontact 0.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/.document +5 -0
- data/.gitignore +6 -0
- data/LICENSE +20 -0
- data/README.markdown +196 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/acts_as_icontact.gemspec +74 -0
- data/lib/acts_as_icontact.rb +19 -0
- data/lib/acts_as_icontact/config.rb +106 -0
- data/lib/acts_as_icontact/connection.rb +32 -0
- data/lib/acts_as_icontact/exceptions.rb +19 -0
- data/lib/acts_as_icontact/resource.rb +204 -0
- data/lib/acts_as_icontact/resource_collection.rb +27 -0
- data/lib/acts_as_icontact/resources/account.rb +38 -0
- data/lib/acts_as_icontact/resources/client.rb +45 -0
- data/lib/acts_as_icontact/resources/contact.rb +7 -0
- data/spec/config_spec.rb +181 -0
- data/spec/connection_spec.rb +36 -0
- data/spec/resource_collection_spec.rb +23 -0
- data/spec/resource_spec.rb +301 -0
- data/spec/resources/account_spec.rb +52 -0
- data/spec/resources/client_spec.rb +52 -0
- data/spec/resources/contact_spec.rb +8 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_fakeweb.rb +23 -0
- data/spec/spec_helper.rb +18 -0
- metadata +93 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe ActsAsIcontact, "connection method" do
|
4
|
+
it "returns a RestClient resource" do
|
5
|
+
ActsAsIcontact.connection.should be_a_kind_of(RestClient::Resource)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "throws an error if no username is given" do
|
9
|
+
ActsAsIcontact::Config.expects(:username).returns(nil)
|
10
|
+
lambda{ActsAsIcontact.connection}.should raise_error(ActsAsIcontact::ConfigError, "Username is required")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "throws an error if no password is given" do
|
14
|
+
ActsAsIcontact::Config.expects(:password).returns(nil)
|
15
|
+
lambda{ActsAsIcontact.connection}.should raise_error(ActsAsIcontact::ConfigError, "Password is required")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can be cleared with the reset_client! method" do
|
19
|
+
RestClient::Resource.expects(:new).returns(true)
|
20
|
+
ActsAsIcontact.reset_connection!
|
21
|
+
ActsAsIcontact.connection.should_not be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "resets the account when reset_client! is called" do
|
25
|
+
ActsAsIcontact.expects(:reset_account!).at_least_once.returns(nil)
|
26
|
+
ActsAsIcontact.reset_connection!
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can be used to make calls to the iContact server" do
|
30
|
+
ActsAsIcontact.connection['time'].get.should =~ /"timestamp":\d+/
|
31
|
+
end
|
32
|
+
|
33
|
+
after(:each) do
|
34
|
+
ActsAsIcontact.reset_connection!
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe ActsAsIcontact::ResourceCollection do
|
4
|
+
before(:each) do
|
5
|
+
@dummy = {"total"=>2, "resources"=>[{"foo"=>"bar"}, {"yoo"=>"yar"}], "limit"=>20, "offset"=>0}
|
6
|
+
@this = ActsAsIcontact::ResourceCollection.new(ActsAsIcontact::Resource, @dummy)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "takes a resource class and a parsed JSON collection" do
|
10
|
+
@this.should be_a_kind_of(ActsAsIcontact::ResourceCollection)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns an object of the resource class for each element" do
|
14
|
+
@this.each do |element|
|
15
|
+
element.should be_a_kind_of(ActsAsIcontact::Resource)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can return an element at a specified index" do
|
20
|
+
@this[1].yoo.should == "yar"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,301 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe ActsAsIcontact::Resource do
|
4
|
+
it "has a RestClient connection" do
|
5
|
+
ActsAsIcontact::Resource.connection.url.should == ActsAsIcontact.connection['resources'].url
|
6
|
+
end
|
7
|
+
|
8
|
+
it "can return all resources for the given URL" do
|
9
|
+
ActsAsIcontact::Resource.all.count.should == 12
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can return the first resource" do
|
13
|
+
ActsAsIcontact::Resource.first.should be_a_kind_of(ActsAsIcontact::Resource)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "find method" do
|
17
|
+
it "returns a ResourceCollection when given :all" do
|
18
|
+
r = ActsAsIcontact::Resource.find(:all)
|
19
|
+
r.should be_a_kind_of(ActsAsIcontact::ResourceCollection)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns a Resource when given :first" do
|
23
|
+
r = ActsAsIcontact::Resource.find(:first)
|
24
|
+
r.should be_a_kind_of(ActsAsIcontact::Resource)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "understands the :limit option" do
|
28
|
+
r = ActsAsIcontact::Resource.find(:all, :limit => 5)
|
29
|
+
r.first.foo.should == "bar"
|
30
|
+
r[4].foo.should == "dar"
|
31
|
+
r.count.should == 5
|
32
|
+
end
|
33
|
+
|
34
|
+
it "understands the :offset option" do
|
35
|
+
r = ActsAsIcontact::Resource.find(:all, :offset => 5)
|
36
|
+
r.count.should == 7
|
37
|
+
r.first.foo.should == "ear"
|
38
|
+
r[6].foo.should == "yar"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "understands multiple options together (:limit and :offset)" do
|
42
|
+
r = ActsAsIcontact::Resource.find(:all, :offset => 5, :limit => 5)
|
43
|
+
r.first.foo.should == "ear"
|
44
|
+
r[4].foo.should == "jar"
|
45
|
+
r.count.should == 5
|
46
|
+
end
|
47
|
+
|
48
|
+
it "returns fewer than the limit if it hits the end of the collection" do
|
49
|
+
r = ActsAsIcontact::Resource.find(:all, :offset => 10, :limit => 5)
|
50
|
+
r.count.should == 2
|
51
|
+
r.first.foo.should == "kar"
|
52
|
+
r[1].foo.should == "yar"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "knows its properties" do
|
57
|
+
r = ActsAsIcontact::Resource.first
|
58
|
+
r.foo.should == "bar"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "knows its id if it's not new" do
|
62
|
+
r = ActsAsIcontact::Resource.first
|
63
|
+
r.id.should == 1
|
64
|
+
end
|
65
|
+
|
66
|
+
it "does not have an id if it's new" do
|
67
|
+
r = ActsAsIcontact::Resource.new("foo" => "bar")
|
68
|
+
r.id.should be_nil
|
69
|
+
end
|
70
|
+
|
71
|
+
it "has its own connection if it's not new" do
|
72
|
+
r = ActsAsIcontact::Resource.first
|
73
|
+
r.connection.url.should == ActsAsIcontact.connection['resources/1'].url
|
74
|
+
end
|
75
|
+
|
76
|
+
it "does not have a connection if it's new" do
|
77
|
+
r = ActsAsIcontact::Resource.new("foo" => "bar")
|
78
|
+
r.connection.should be_nil
|
79
|
+
end
|
80
|
+
|
81
|
+
it "knows its REST base resource" do
|
82
|
+
ActsAsIcontact::Resource.base.should == ActsAsIcontact.connection
|
83
|
+
end
|
84
|
+
|
85
|
+
it "knows its primary key" do
|
86
|
+
ActsAsIcontact::Resource.primary_key.should == "resourceId"
|
87
|
+
end
|
88
|
+
|
89
|
+
it "knows that the primary key is required on update" do
|
90
|
+
ActsAsIcontact::Resource.required_on_update.should == ["resourceId"]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "knows that the primary key MUST NOT be included on create" do
|
94
|
+
ActsAsIcontact::Resource.never_on_create.should == ["resourceId"]
|
95
|
+
end
|
96
|
+
|
97
|
+
context "updating records" do
|
98
|
+
before(:each) do
|
99
|
+
@res = ActsAsIcontact::Resource.first
|
100
|
+
end
|
101
|
+
it "knows it isn't a new record" do
|
102
|
+
@res.should_not be_a_new_record
|
103
|
+
end
|
104
|
+
|
105
|
+
it "can set new values on existing fields" do
|
106
|
+
@res.foo = "zar"
|
107
|
+
@res.foo.should == "zar"
|
108
|
+
end
|
109
|
+
|
110
|
+
it "can add new fields" do
|
111
|
+
@res.zoo = "flar"
|
112
|
+
@res.zoo.should == "flar"
|
113
|
+
end
|
114
|
+
|
115
|
+
it "knows the minimum set of properties that changed or must be sent" do
|
116
|
+
@res.too = "tar"
|
117
|
+
@res.send(:update_fields).should == {"resourceId" => "1", "too" => "tar"}
|
118
|
+
end
|
119
|
+
|
120
|
+
context "with successful save" do
|
121
|
+
before(:each) do
|
122
|
+
@res.too = "sar"
|
123
|
+
@result = @res.save
|
124
|
+
end
|
125
|
+
|
126
|
+
it "returns success" do
|
127
|
+
@result.should be_true
|
128
|
+
end
|
129
|
+
|
130
|
+
it "updates itself with the new values" do
|
131
|
+
@res.too.should == "sar"
|
132
|
+
end
|
133
|
+
|
134
|
+
it "has no errors" do
|
135
|
+
@res.errors.should be_empty
|
136
|
+
end
|
137
|
+
|
138
|
+
it "has no error" do
|
139
|
+
@res.error.should be_nil
|
140
|
+
end
|
141
|
+
|
142
|
+
it "can be called with a bang" do
|
143
|
+
@res.save!.should be_true
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "with failed save but status 200" do
|
148
|
+
before(:each) do
|
149
|
+
@bad = ActsAsIcontact::Resource.all[1]
|
150
|
+
@bad.foo = nil
|
151
|
+
@result = @bad.save
|
152
|
+
end
|
153
|
+
|
154
|
+
it "returns failure" do
|
155
|
+
@result.should be_false
|
156
|
+
end
|
157
|
+
|
158
|
+
it "returns the errors list" do
|
159
|
+
@bad.errors.should == ["You did not provide a foo. foo is a required field. Please provide a foo","This was not a good record"]
|
160
|
+
end
|
161
|
+
|
162
|
+
it "returns the top error" do
|
163
|
+
@bad.error.should == "You did not provide a foo. foo is a required field. Please provide a foo"
|
164
|
+
end
|
165
|
+
|
166
|
+
it "throws an exception with a bang" do
|
167
|
+
lambda{@bad.save!}.should raise_error(ActsAsIcontact::RecordNotSaved,"You did not provide a foo. foo is a required field. Please provide a foo")
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "with failed save on HTTP failure exception" do
|
172
|
+
before(:each) do
|
173
|
+
@bad = ActsAsIcontact::Resource.all[2]
|
174
|
+
@bad.foo = nil
|
175
|
+
@result = @bad.save
|
176
|
+
end
|
177
|
+
|
178
|
+
it "returns failure" do
|
179
|
+
@result.should be_false
|
180
|
+
end
|
181
|
+
|
182
|
+
it "returns the errors list" do
|
183
|
+
@bad.errors.should == ["You did not provide a clue. Clue is a required field. Please provide a clue"]
|
184
|
+
end
|
185
|
+
|
186
|
+
it "returns the top error" do
|
187
|
+
@bad.error.should == "You did not provide a clue. Clue is a required field. Please provide a clue"
|
188
|
+
end
|
189
|
+
|
190
|
+
it "throws an exception with a bang" do
|
191
|
+
lambda{@bad.save!}.should raise_error(ActsAsIcontact::RecordNotSaved,"You did not provide a clue. Clue is a required field. Please provide a clue")
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
context "creating records" do
|
198
|
+
before(:each) do
|
199
|
+
@res = ActsAsIcontact::Resource.new("foo" => "flar", "kroo" => "krar")
|
200
|
+
end
|
201
|
+
it "knows it's a new record" do
|
202
|
+
@res.should be_a_new_record
|
203
|
+
end
|
204
|
+
|
205
|
+
it "can set new values on existing fields" do
|
206
|
+
@res.foo = "zar"
|
207
|
+
@res.foo.should == "zar"
|
208
|
+
end
|
209
|
+
|
210
|
+
it "can add new fields" do
|
211
|
+
@res.zoo = "flar"
|
212
|
+
@res.zoo.should == "flar"
|
213
|
+
end
|
214
|
+
|
215
|
+
it "knows the full set of properties that were added or are required" do
|
216
|
+
ActsAsIcontact::Resource.stubs(:required_on_create).returns(["shoo"])
|
217
|
+
@res.send(:create_fields).should == {"foo" => "flar", "kroo" => "krar", "shoo" => ""}
|
218
|
+
end
|
219
|
+
|
220
|
+
context "with successful save" do
|
221
|
+
before(:each) do
|
222
|
+
FakeWeb.register_uri(:post, "https://app.beta.icontact.com/icp/resources", :body => %q<{"resources":[{"resourceId":"100","foo":"flar","kroo":"krar","too":"sar"}]}>)
|
223
|
+
@res.too = "sar"
|
224
|
+
end
|
225
|
+
|
226
|
+
it "returns success" do
|
227
|
+
@res.save.should be_true
|
228
|
+
end
|
229
|
+
|
230
|
+
it "updates itself with the new values" do
|
231
|
+
@res.save
|
232
|
+
@res.too.should == "sar"
|
233
|
+
end
|
234
|
+
|
235
|
+
it "has no errors" do
|
236
|
+
@res.save
|
237
|
+
@res.errors.should be_empty
|
238
|
+
end
|
239
|
+
|
240
|
+
it "has no error" do
|
241
|
+
@res.save
|
242
|
+
@res.error.should be_nil
|
243
|
+
end
|
244
|
+
|
245
|
+
it "can be called with a bang" do
|
246
|
+
@res.save!.should be_true
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context "with failed save but status 200" do
|
251
|
+
before(:each) do
|
252
|
+
FakeWeb.register_uri(:post, "https://app.beta.icontact.com/icp/resources", :body => %q<{"resources":[],"warnings":["You did not provide a foo. foo is a required field. Please provide a foo","This was not a good record"]}>)
|
253
|
+
@res = ActsAsIcontact::Resource.new
|
254
|
+
@res.foo = nil
|
255
|
+
@result = @res.save
|
256
|
+
end
|
257
|
+
|
258
|
+
it "returns failure" do
|
259
|
+
@result.should be_false
|
260
|
+
end
|
261
|
+
|
262
|
+
it "returns the errors list" do
|
263
|
+
@res.errors.should == ["You did not provide a foo. foo is a required field. Please provide a foo","This was not a good record"]
|
264
|
+
end
|
265
|
+
|
266
|
+
it "returns the top error" do
|
267
|
+
@res.error.should == "You did not provide a foo. foo is a required field. Please provide a foo"
|
268
|
+
end
|
269
|
+
|
270
|
+
it "throws an exception with a bang" do
|
271
|
+
lambda{@res.save!}.should raise_error(ActsAsIcontact::RecordNotSaved,"You did not provide a foo. foo is a required field. Please provide a foo")
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
context "with failed save on HTTP failure exception" do
|
276
|
+
before(:each) do
|
277
|
+
FakeWeb.register_uri(:post, "https://app.beta.icontact.com/icp/resources", :status => ["400","Bad Request"], :body => %q<{"errors":["You did not provide a clue. Clue is a required field. Please provide a clue"]}>)
|
278
|
+
@res = ActsAsIcontact::Resource.new
|
279
|
+
@res.foo = nil
|
280
|
+
@result = @res.save
|
281
|
+
end
|
282
|
+
|
283
|
+
it "returns failure" do
|
284
|
+
@result.should be_false
|
285
|
+
end
|
286
|
+
|
287
|
+
it "returns the errors list" do
|
288
|
+
@res.errors.should == ["You did not provide a clue. Clue is a required field. Please provide a clue"]
|
289
|
+
end
|
290
|
+
|
291
|
+
it "returns the top error" do
|
292
|
+
@res.error.should == "You did not provide a clue. Clue is a required field. Please provide a clue"
|
293
|
+
end
|
294
|
+
|
295
|
+
it "throws an exception with a bang" do
|
296
|
+
lambda{@res.save!}.should raise_error(ActsAsIcontact::RecordNotSaved,"You did not provide a clue. Clue is a required field. Please provide a clue")
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
end
|
301
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe ActsAsIcontact, "account_id" do
|
4
|
+
it "returns the ID from the first account returned by iContact" do
|
5
|
+
ActsAsIcontact.account_id.should == 111111
|
6
|
+
end
|
7
|
+
|
8
|
+
it "can be set by the user" do
|
9
|
+
ActsAsIcontact.account_id = 345
|
10
|
+
ActsAsIcontact.account_id.should == 345
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:each) do
|
14
|
+
ActsAsIcontact.account_id = nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
describe ActsAsIcontact, "account method" do
|
20
|
+
it "returns a RestClient resource" do
|
21
|
+
ActsAsIcontact.account.should be_a_kind_of(RestClient::Resource)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "builds upon the 'connection' object" do
|
25
|
+
ActsAsIcontact.expects(:connection).returns(ActsAsIcontact.instance_variable_get(:@connection))
|
26
|
+
ActsAsIcontact.account.should_not be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can be cleared with the reset_account! method" do
|
30
|
+
ActsAsIcontact.reset_account!
|
31
|
+
ActsAsIcontact.instance_variable_get(:@account).should be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
after(:each) do
|
35
|
+
ActsAsIcontact.reset_account!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe ActsAsIcontact::Account do
|
40
|
+
it "can return all accounts" do
|
41
|
+
ActsAsIcontact::Account.all.count.should == 1
|
42
|
+
end
|
43
|
+
|
44
|
+
it "can return the first account" do
|
45
|
+
ActsAsIcontact::Account.first.should be_a_kind_of(ActsAsIcontact::Account)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "knows its attributes" do
|
49
|
+
a = ActsAsIcontact::Account.first
|
50
|
+
a.firstName.should == "Bob"
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe ActsAsIcontact, "account_id" do
|
4
|
+
it "returns the ID from the first client folder returned by iContact" do
|
5
|
+
ActsAsIcontact.client_id.should == 222222
|
6
|
+
end
|
7
|
+
|
8
|
+
it "can be set by the user" do
|
9
|
+
ActsAsIcontact.client_id = 456
|
10
|
+
ActsAsIcontact.client_id.should == 456
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:each) do
|
14
|
+
ActsAsIcontact.client_id = nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
describe ActsAsIcontact, "client method" do
|
20
|
+
it "returns a RestClient resource" do
|
21
|
+
ActsAsIcontact.client.should be_a_kind_of(RestClient::Resource)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "builds upon the 'account' object" do
|
25
|
+
ActsAsIcontact.expects(:account).returns(ActsAsIcontact.instance_variable_get(:@account))
|
26
|
+
ActsAsIcontact.client.should_not be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can be cleared with the reset_account! method" do
|
30
|
+
ActsAsIcontact.reset_client!
|
31
|
+
ActsAsIcontact.instance_variable_get(:@client).should be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
after(:each) do
|
35
|
+
ActsAsIcontact.reset_client!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe ActsAsIcontact::Client do
|
40
|
+
it "can return all clients for the given account" do
|
41
|
+
ActsAsIcontact::Client.all.count.should == 1
|
42
|
+
end
|
43
|
+
|
44
|
+
it "can return the first client" do
|
45
|
+
ActsAsIcontact::Client.first.should be_a_kind_of(ActsAsIcontact::Client)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "knows its properties" do
|
49
|
+
c = ActsAsIcontact::Client.first
|
50
|
+
c.emailRecipient.should == "bob@example.org"
|
51
|
+
end
|
52
|
+
end
|