customerio 5.6.0 → 6.0.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 +4 -4
- data/CHANGELOG.markdown +5 -0
- data/README.md +144 -12
- data/lib/customerio/api.rb +47 -57
- data/lib/customerio/base_client.rb +26 -20
- data/lib/customerio/client.rb +142 -75
- data/lib/customerio/param_encoder.rb +6 -11
- data/lib/customerio/regions.rb +3 -4
- data/lib/customerio/requests/send_email_request.rb +22 -23
- data/lib/customerio/requests/send_in_app_request.rb +12 -16
- data/lib/customerio/requests/send_inbox_message_request.rb +12 -16
- data/lib/customerio/requests/send_push_request.rb +16 -14
- data/lib/customerio/requests/send_sms_request.rb +21 -23
- data/lib/customerio/requests/trigger_broadcast_request.rb +28 -0
- data/lib/customerio/version.rb +3 -1
- data/lib/customerio.rb +3 -0
- metadata +14 -95
- data/.github/workflows/main.yml +0 -21
- data/.gitignore +0 -20
- data/.gitpod.yml +0 -10
- data/Gemfile +0 -4
- data/Rakefile +0 -8
- data/customerio.gemspec +0 -27
- data/spec/api_client_spec.rb +0 -432
- data/spec/base_client_spec.rb +0 -67
- data/spec/client_spec.rb +0 -718
- data/spec/spec_helper.rb +0 -15
data/spec/client_spec.rb
DELETED
|
@@ -1,718 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'multi_json'
|
|
3
|
-
require 'base64'
|
|
4
|
-
|
|
5
|
-
describe Customerio::Client do
|
|
6
|
-
let(:site_id) { "SITE_ID" }
|
|
7
|
-
let(:api_key) { "API_KEY" }
|
|
8
|
-
|
|
9
|
-
let(:client) { Customerio::Client.new(site_id, api_key) }
|
|
10
|
-
let(:response) { double("Response", code: 200) }
|
|
11
|
-
|
|
12
|
-
def api_uri(path)
|
|
13
|
-
"https://track.customer.io#{path}"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def request_headers
|
|
17
|
-
token = Base64.strict_encode64("#{site_id}:#{api_key}")
|
|
18
|
-
{ 'Authorization': "Basic #{token}", 'Content-Type': 'application/json' }
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def json(data)
|
|
22
|
-
MultiJson.dump(data)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it "the base client is initialised with the correct values when no region is passed in" do
|
|
26
|
-
site_id = "SITE_ID"
|
|
27
|
-
api_key = "API_KEY"
|
|
28
|
-
|
|
29
|
-
expect(Customerio::BaseClient).to(
|
|
30
|
-
receive(:new)
|
|
31
|
-
.with(
|
|
32
|
-
{ site_id: site_id, api_key: api_key },
|
|
33
|
-
{
|
|
34
|
-
region: Customerio::Regions::US,
|
|
35
|
-
url: Customerio::Regions::US.track_url
|
|
36
|
-
}
|
|
37
|
-
)
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
client = Customerio::Client.new(site_id, api_key)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
it "raises an error when an incorrect region is passed in" do
|
|
44
|
-
expect {
|
|
45
|
-
Customerio::Client.new("siteid", "apikey", region: :au)
|
|
46
|
-
}.to raise_error /region must be an instance of Customerio::Regions::Region/
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
[Customerio::Regions::US, Customerio::Regions::EU].each do |region|
|
|
50
|
-
it "the base client is initialised with the correct values when the region \"#{region}\" is passed in" do
|
|
51
|
-
site_id = "SITE_ID"
|
|
52
|
-
api_key = "API_KEY"
|
|
53
|
-
|
|
54
|
-
expect(Customerio::BaseClient).to(
|
|
55
|
-
receive(:new)
|
|
56
|
-
.with(
|
|
57
|
-
{ site_id: site_id, api_key: api_key },
|
|
58
|
-
{
|
|
59
|
-
region: region,
|
|
60
|
-
url: region.track_url
|
|
61
|
-
}
|
|
62
|
-
)
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
client = Customerio::Client.new(site_id, api_key, { region: region })
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
it "uses json by default" do
|
|
70
|
-
body = { id: 5, name: "Bob" }
|
|
71
|
-
client = Customerio::Client.new("SITE_ID", "API_KEY")
|
|
72
|
-
|
|
73
|
-
stub_request(:put, api_uri('/api/v1/customers/5')).
|
|
74
|
-
with(body: json(body),
|
|
75
|
-
headers: {'Content-Type'=>'application/json'}).
|
|
76
|
-
to_return(status: 200, body: "", headers: {})
|
|
77
|
-
|
|
78
|
-
client.identify(body)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
describe "headers" do
|
|
82
|
-
let(:body) { { id: 1, token: :test } }
|
|
83
|
-
|
|
84
|
-
it "sends the basic headers, base64 encoded with the request" do
|
|
85
|
-
client = Customerio::Client.new("SITE_ID", "API_KEY")
|
|
86
|
-
|
|
87
|
-
stub_request(:put, api_uri('/api/v1/customers/1')).
|
|
88
|
-
with(body: json(body), headers: request_headers).
|
|
89
|
-
to_return(status: 200, body: "", headers: {})
|
|
90
|
-
|
|
91
|
-
client.identify(body)
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
describe "#identify" do
|
|
96
|
-
it "sends a PUT request to customer.io's customer API" do
|
|
97
|
-
stub_request(:put, api_uri('/api/v1/customers/5')).
|
|
98
|
-
with(body: json(id: "5")).
|
|
99
|
-
to_return(status: 200, body: "", headers: {})
|
|
100
|
-
|
|
101
|
-
client.identify(id: "5")
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
it "escapes customer IDs" do
|
|
105
|
-
stub_request(:put, api_uri('/api/v1/customers/5%20')).
|
|
106
|
-
with(body: json({ id: "5 " })).
|
|
107
|
-
to_return(status: 200, body: "", headers: {})
|
|
108
|
-
|
|
109
|
-
client.identify(id: "5 ")
|
|
110
|
-
|
|
111
|
-
stub_request(:put, api_uri('/api/v1/customers/5%2F')).
|
|
112
|
-
with(body: { id: "5/" }).
|
|
113
|
-
to_return(status: 200, body: "", headers: {})
|
|
114
|
-
client.identify(id: "5/")
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
it "sends a PUT request to customer.io's customer API using json headers" do
|
|
118
|
-
client = Customerio::Client.new("SITE_ID", "API_KEY", json: true)
|
|
119
|
-
body = { id: 5, name: "Bob" }
|
|
120
|
-
|
|
121
|
-
stub_request(:put, api_uri('/api/v1/customers/5')).
|
|
122
|
-
with(body: json(body),
|
|
123
|
-
headers: {'Content-Type'=>'application/json'}).
|
|
124
|
-
to_return(status: 200, body: "", headers: {})
|
|
125
|
-
|
|
126
|
-
client.identify(body)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
it "raises an error if PUT doesn't return a 2xx response code" do
|
|
130
|
-
stub_request(:put, api_uri('/api/v1/customers/5')).
|
|
131
|
-
with(body: json(id: 5)).
|
|
132
|
-
to_return(status: 500, body: "", headers: {})
|
|
133
|
-
|
|
134
|
-
lambda { client.identify(id: 5) }.should raise_error(Customerio::InvalidResponse)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
it "includes the HTTP response with raised errors" do
|
|
138
|
-
stub_request(:put, api_uri('/api/v1/customers/5')).
|
|
139
|
-
with(body: json(id: 5)).
|
|
140
|
-
to_return(status: 500, body: "Server unavailable", headers: {})
|
|
141
|
-
|
|
142
|
-
lambda { client.identify(id: 5) }.should raise_error {|error|
|
|
143
|
-
error.should be_a Customerio::InvalidResponse
|
|
144
|
-
error.code.should eq "500"
|
|
145
|
-
error.message.should eq "Server unavailable"
|
|
146
|
-
}
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
it "sends along all attributes" do
|
|
150
|
-
time = Time.now.to_i
|
|
151
|
-
|
|
152
|
-
stub_request(:put, api_uri('/api/v1/customers/5')).with(
|
|
153
|
-
body: {
|
|
154
|
-
id: 5,
|
|
155
|
-
email: "customer@example.com",
|
|
156
|
-
created_at: time,
|
|
157
|
-
first_name: "Bob",
|
|
158
|
-
plan: "basic",
|
|
159
|
-
anonymous_id: "anon-id"
|
|
160
|
-
}).to_return(status: 200, body: "", headers: {})
|
|
161
|
-
|
|
162
|
-
client.identify({
|
|
163
|
-
id: 5,
|
|
164
|
-
anonymous_id: "anon-id",
|
|
165
|
-
email: "customer@example.com",
|
|
166
|
-
created_at: time,
|
|
167
|
-
first_name: "Bob",
|
|
168
|
-
plan: "basic"
|
|
169
|
-
})
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
it "requires an id attribute" do
|
|
173
|
-
lambda { client.identify(email: "customer@example.com") }.should raise_error(Customerio::Client::MissingIdAttributeError)
|
|
174
|
-
lambda { client.identify(id: "") }.should raise_error(Customerio::Client::MissingIdAttributeError)
|
|
175
|
-
lambda { client.identify(cio_id: "") }.should raise_error(Customerio::Client::MissingIdAttributeError)
|
|
176
|
-
lambda { client.identify(customer_id: "") }.should raise_error(Customerio::Client::MissingIdAttributeError)
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
it 'should not raise errors when attribute keys are strings' do
|
|
180
|
-
stub_request(:put, api_uri('/api/v1/customers/5')).
|
|
181
|
-
with(body: json(id: 5)).
|
|
182
|
-
to_return(status: 200, body: "", headers: {})
|
|
183
|
-
|
|
184
|
-
attributes = { "id" => 5 }
|
|
185
|
-
|
|
186
|
-
lambda { client.identify(attributes) }.should_not raise_error()
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
it 'uses cio_id for customer id, when present, for id updates' do
|
|
190
|
-
stub_request(:put, api_uri('/api/v1/customers/cio_347f00d')).with(
|
|
191
|
-
body: {
|
|
192
|
-
cio_id: "347f00d",
|
|
193
|
-
id: 5
|
|
194
|
-
}).to_return(status: 200, body: "", headers: {})
|
|
195
|
-
|
|
196
|
-
client.identify({
|
|
197
|
-
cio_id: "347f00d",
|
|
198
|
-
id: 5
|
|
199
|
-
})
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
it 'uses cio_id for customer id, when present, for email updates' do
|
|
203
|
-
stub_request(:put, api_uri('/api/v1/customers/cio_347f00d')).with(
|
|
204
|
-
body: {
|
|
205
|
-
cio_id: "347f00d",
|
|
206
|
-
email: "different.customer@example.com"
|
|
207
|
-
}).to_return(status: 200, body: "", headers: {})
|
|
208
|
-
|
|
209
|
-
client.identify({
|
|
210
|
-
cio_id: "347f00d",
|
|
211
|
-
email: "different.customer@example.com"
|
|
212
|
-
})
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
it 'allows updates with cio_id as the only id' do
|
|
216
|
-
stub_request(:put, api_uri('/api/v1/customers/cio_347f00d')).with(
|
|
217
|
-
body: {
|
|
218
|
-
cio_id: "347f00d",
|
|
219
|
-
location: "here"
|
|
220
|
-
}).to_return(status: 200, body: "", headers: {})
|
|
221
|
-
|
|
222
|
-
client.identify({
|
|
223
|
-
cio_id: "347f00d",
|
|
224
|
-
location: "here"
|
|
225
|
-
})
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
it "uses provided id rather than id" do
|
|
229
|
-
stub_request(:put, api_uri('/api/v1/customers/1234')).
|
|
230
|
-
with(body: json(id: "5")).
|
|
231
|
-
to_return(status: 200, body: "", headers: {})
|
|
232
|
-
|
|
233
|
-
client.identify(
|
|
234
|
-
customer_id: "1234",
|
|
235
|
-
id: "5"
|
|
236
|
-
)
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
it "uses provided cio_id rather than id" do
|
|
240
|
-
stub_request(:put, api_uri('/api/v1/customers/cio_5')).
|
|
241
|
-
with(body: json(id: "5")).
|
|
242
|
-
to_return(status: 200, body: "", headers: {})
|
|
243
|
-
|
|
244
|
-
client.identify(
|
|
245
|
-
customer_id: "cio_5",
|
|
246
|
-
id: "5"
|
|
247
|
-
)
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
it "uses provided email rather than id" do
|
|
251
|
-
stub_request(:put, api_uri('/api/v1/customers/customer@example.com')).
|
|
252
|
-
with(body: json(id: "5")).
|
|
253
|
-
to_return(status: 200, body: "", headers: {})
|
|
254
|
-
|
|
255
|
-
client.identify(
|
|
256
|
-
customer_id: "customer@example.com",
|
|
257
|
-
id: "5"
|
|
258
|
-
)
|
|
259
|
-
end
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
describe "#delete" do
|
|
263
|
-
it "sends a DELETE request to the customer.io's event API" do
|
|
264
|
-
stub_request(:delete, api_uri('/api/v1/customers/5')).
|
|
265
|
-
to_return(status: 200, body: "", headers: {})
|
|
266
|
-
|
|
267
|
-
client.delete(5)
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
it "throws an error when customer_id is missing" do
|
|
271
|
-
stub_request(:put, /track.customer.io/)
|
|
272
|
-
.to_return(status: 200, body: "", headers: {})
|
|
273
|
-
|
|
274
|
-
lambda { client.delete(" ") }.should raise_error(Customerio::Client::ParamError, "customer_id must be a non-empty string")
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
it "escapes customer IDs" do
|
|
278
|
-
stub_request(:delete, api_uri('/api/v1/customers/5%20')).
|
|
279
|
-
to_return(status: 200, body: "", headers: {})
|
|
280
|
-
|
|
281
|
-
client.delete("5 ")
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
describe "#suppress" do
|
|
286
|
-
it "sends a POST request to the customer.io's suppress API" do
|
|
287
|
-
stub_request(:post, api_uri('/api/v1/customers/5/suppress')).
|
|
288
|
-
to_return(status: 200, body: "", headers: {})
|
|
289
|
-
|
|
290
|
-
client.suppress(5)
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
it "throws an error when customer_id is missing" do
|
|
294
|
-
stub_request(:put, /track.customer.io/)
|
|
295
|
-
.to_return(status: 200, body: "", headers: {})
|
|
296
|
-
|
|
297
|
-
lambda { client.suppress(" ") }.should raise_error(Customerio::Client::ParamError, "customer_id must be a non-empty string")
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
describe "#unsuppress" do
|
|
302
|
-
it "sends a POST request to the customer.io's unsuppress API" do
|
|
303
|
-
stub_request(:post, api_uri('/api/v1/customers/5/unsuppress')).
|
|
304
|
-
to_return(status: 200, body: "", headers: {})
|
|
305
|
-
|
|
306
|
-
client.unsuppress(5)
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
it "throws an error when customer_id is missing" do
|
|
310
|
-
stub_request(:put, /track.customer.io/)
|
|
311
|
-
.to_return(status: 200, body: "", headers: {})
|
|
312
|
-
|
|
313
|
-
lambda { client.suppress(" ") }.should raise_error(Customerio::Client::ParamError, "customer_id must be a non-empty string")
|
|
314
|
-
end
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
describe "#pageview" do
|
|
318
|
-
it "allows sending pageview event" do
|
|
319
|
-
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
|
320
|
-
with(body: json(name: "http://customer.io", data: {}, type: "page")).
|
|
321
|
-
to_return(status: 200, body: "", headers: {})
|
|
322
|
-
|
|
323
|
-
client.pageview(5, "http://customer.io")
|
|
324
|
-
end
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
describe "#track" do
|
|
328
|
-
it "raises an error if POST doesn't return a 2xx response code" do
|
|
329
|
-
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
|
330
|
-
with(body: json(name: "purchase", data: {})).
|
|
331
|
-
to_return(status: 500, body: "", headers: {})
|
|
332
|
-
|
|
333
|
-
lambda { client.track(5, "purchase") }.should raise_error(Customerio::InvalidResponse)
|
|
334
|
-
end
|
|
335
|
-
|
|
336
|
-
it "throws an error when customer_id or event_name is missing" do
|
|
337
|
-
stub_request(:put, /track.customer.io/)
|
|
338
|
-
.to_return(status: 200, body: "", headers: {})
|
|
339
|
-
|
|
340
|
-
lambda { client.track(" ", "test_event") }.should raise_error(Customerio::Client::ParamError, "customer_id must be a non-empty string")
|
|
341
|
-
lambda { client.track(5, " ") }.should raise_error(Customerio::Client::ParamError, "event_name must be a non-empty string")
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
it "uses the site_id and api key for basic auth and sends the event name" do
|
|
345
|
-
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
|
346
|
-
with(body: json(name: "purchase", data: {})).
|
|
347
|
-
to_return(status: 200, body: "", headers: {})
|
|
348
|
-
|
|
349
|
-
client.track(5, "purchase")
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
it "sends any optional event attributes" do
|
|
353
|
-
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
|
354
|
-
with(body: json({
|
|
355
|
-
name: "purchase",
|
|
356
|
-
data: {
|
|
357
|
-
type: "socks",
|
|
358
|
-
price: "13.99"
|
|
359
|
-
}
|
|
360
|
-
})).
|
|
361
|
-
to_return(status: 200, body: "", headers: {})
|
|
362
|
-
|
|
363
|
-
client.track(5, "purchase", type: "socks", price: "13.99")
|
|
364
|
-
end
|
|
365
|
-
|
|
366
|
-
it "copes with arrays" do
|
|
367
|
-
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
|
368
|
-
with(body: {
|
|
369
|
-
name: "event",
|
|
370
|
-
data: {
|
|
371
|
-
things: ["a", "b", "c"]
|
|
372
|
-
}
|
|
373
|
-
}).
|
|
374
|
-
to_return(status: 200, body: "", headers: {})
|
|
375
|
-
|
|
376
|
-
client.track(5, "event", things: ["a", "b", "c"])
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
it "copes with hashes" do
|
|
380
|
-
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
|
381
|
-
with(body: {
|
|
382
|
-
name: "event",
|
|
383
|
-
data: {
|
|
384
|
-
stuff: { a: "b" }
|
|
385
|
-
}
|
|
386
|
-
}).
|
|
387
|
-
to_return(status: 200, body: "", headers: {})
|
|
388
|
-
|
|
389
|
-
client.track(5, "event", stuff: { a: "b" })
|
|
390
|
-
end
|
|
391
|
-
|
|
392
|
-
it "sends a POST request as json using json headers" do
|
|
393
|
-
client = Customerio::Client.new("SITE_ID", "API_KEY", json: true)
|
|
394
|
-
data = { type: "socks", price: "13.99" }
|
|
395
|
-
body = { name: "purchase", data: data }
|
|
396
|
-
|
|
397
|
-
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
|
398
|
-
with(body: json(body),
|
|
399
|
-
headers: {'Content-Type'=>'application/json'}).
|
|
400
|
-
to_return(status: 200, body: "", headers: {})
|
|
401
|
-
|
|
402
|
-
client.track(5, "purchase", data)
|
|
403
|
-
end
|
|
404
|
-
|
|
405
|
-
it "allows sending of a timestamp" do
|
|
406
|
-
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
|
407
|
-
with(body: json({
|
|
408
|
-
name: "purchase",
|
|
409
|
-
data: {
|
|
410
|
-
type: "socks",
|
|
411
|
-
price: "13.99",
|
|
412
|
-
timestamp: 1561231234
|
|
413
|
-
},
|
|
414
|
-
timestamp: 1561231234
|
|
415
|
-
})).
|
|
416
|
-
to_return(status: 200, body: "", headers: {})
|
|
417
|
-
|
|
418
|
-
client.track(5, "purchase", type: "socks", price: "13.99", timestamp: 1561231234)
|
|
419
|
-
end
|
|
420
|
-
|
|
421
|
-
it "doesn't send timestamp if timestamp is in milliseconds" do
|
|
422
|
-
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
|
423
|
-
with(body: json({
|
|
424
|
-
name: "purchase",
|
|
425
|
-
data: {
|
|
426
|
-
type: "socks",
|
|
427
|
-
price: "13.99",
|
|
428
|
-
timestamp: 1561231234000
|
|
429
|
-
}
|
|
430
|
-
})).
|
|
431
|
-
to_return(status: 200, body: "", headers: {})
|
|
432
|
-
|
|
433
|
-
client.track(5, "purchase", type: "socks", price: "13.99", timestamp: 1561231234000)
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
it "doesn't send timestamp if timestamp is a date" do
|
|
437
|
-
date = Time.now
|
|
438
|
-
|
|
439
|
-
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
|
440
|
-
with(body: {
|
|
441
|
-
name: "purchase",
|
|
442
|
-
data: {
|
|
443
|
-
type: "socks",
|
|
444
|
-
price: "13.99",
|
|
445
|
-
timestamp: Time.now.to_s
|
|
446
|
-
}
|
|
447
|
-
}).
|
|
448
|
-
to_return(status: 200, body: "", headers: {})
|
|
449
|
-
|
|
450
|
-
client.track(5, "purchase", type: "socks", price: "13.99", timestamp: date)
|
|
451
|
-
end
|
|
452
|
-
|
|
453
|
-
it "doesn't send timestamp if timestamp isn't an integer" do
|
|
454
|
-
stub_request(:post, api_uri('/api/v1/customers/5/events')).
|
|
455
|
-
with(body: json({
|
|
456
|
-
name: "purchase",
|
|
457
|
-
data: {
|
|
458
|
-
type: "socks",
|
|
459
|
-
price: "13.99",
|
|
460
|
-
timestamp: "Hello world"
|
|
461
|
-
}
|
|
462
|
-
})).
|
|
463
|
-
|
|
464
|
-
to_return(status: 200, body: "", headers: {})
|
|
465
|
-
|
|
466
|
-
client.track(5, "purchase", type: "socks", price: "13.99", timestamp: "Hello world")
|
|
467
|
-
end
|
|
468
|
-
|
|
469
|
-
context "tracking an anonymous event" do
|
|
470
|
-
let(:anon_id) { "anon-id" }
|
|
471
|
-
|
|
472
|
-
it "sends a POST request to the customer.io's anonymous event API" do
|
|
473
|
-
stub_request(:post, api_uri('/api/v1/events')).
|
|
474
|
-
with(body: { anonymous_id: anon_id, name: "purchase", data: {} }).
|
|
475
|
-
to_return(status: 200, body: "", headers: {})
|
|
476
|
-
|
|
477
|
-
client.track_anonymous(anon_id, "purchase")
|
|
478
|
-
end
|
|
479
|
-
|
|
480
|
-
it "sends any optional event attributes" do
|
|
481
|
-
stub_request(:post, api_uri('/api/v1/events')).
|
|
482
|
-
with(body: {
|
|
483
|
-
anonymous_id: anon_id,
|
|
484
|
-
name: "purchase",
|
|
485
|
-
data: {
|
|
486
|
-
type: "socks",
|
|
487
|
-
price: "13.99"
|
|
488
|
-
}
|
|
489
|
-
}).
|
|
490
|
-
to_return(status: 200, body: "", headers: {})
|
|
491
|
-
|
|
492
|
-
client.track_anonymous(anon_id, "purchase", type: "socks", price: "13.99")
|
|
493
|
-
end
|
|
494
|
-
|
|
495
|
-
it "allows sending of a timestamp" do
|
|
496
|
-
stub_request(:post, api_uri('/api/v1/events')).
|
|
497
|
-
with(body: {
|
|
498
|
-
anonymous_id: anon_id,
|
|
499
|
-
name: "purchase",
|
|
500
|
-
data: {
|
|
501
|
-
type: "socks",
|
|
502
|
-
price: "13.99",
|
|
503
|
-
timestamp: 1561231234
|
|
504
|
-
},
|
|
505
|
-
timestamp: 1561231234
|
|
506
|
-
}).
|
|
507
|
-
to_return(status: 200, body: "", headers: {})
|
|
508
|
-
|
|
509
|
-
client.track_anonymous(anon_id, "purchase", type: "socks", price: "13.99", timestamp: 1561231234)
|
|
510
|
-
end
|
|
511
|
-
|
|
512
|
-
it "raises an error if POST doesn't return a 2xx response code" do
|
|
513
|
-
stub_request(:post, api_uri('/api/v1/events')).
|
|
514
|
-
with(body: { anonymous_id: anon_id, name: "purchase", data: {} }).
|
|
515
|
-
to_return(status: 500, body: "", headers: {})
|
|
516
|
-
|
|
517
|
-
lambda { client.track_anonymous(anon_id, "purchase") }.should raise_error(Customerio::InvalidResponse)
|
|
518
|
-
end
|
|
519
|
-
|
|
520
|
-
it "doesn't pass along anonymous_id if it is blank" do
|
|
521
|
-
stub_request(:post, api_uri('/api/v1/events')).
|
|
522
|
-
with(body: { name: "some_event", data: {} }).
|
|
523
|
-
to_return(status: 200, body: "", headers: {})
|
|
524
|
-
|
|
525
|
-
client.track_anonymous("", "some_event")
|
|
526
|
-
end
|
|
527
|
-
|
|
528
|
-
it "doesn't pass along anonymous_id if it is nil" do
|
|
529
|
-
stub_request(:post, api_uri('/api/v1/events')).
|
|
530
|
-
with(body: { name: "some_event", data: {} }).
|
|
531
|
-
to_return(status: 200, body: "", headers: {})
|
|
532
|
-
|
|
533
|
-
client.track_anonymous(nil, "some_event")
|
|
534
|
-
end
|
|
535
|
-
|
|
536
|
-
it "throws an error when event_name is missing" do
|
|
537
|
-
stub_request(:post, api_uri('/api/v1/events')).
|
|
538
|
-
with(body: { anonymous_id: anon_id, name: "purchase", data: {} }).
|
|
539
|
-
to_return(status: 500, body: "", headers: {})
|
|
540
|
-
|
|
541
|
-
lambda { client.track_anonymous(anon_id, "") }.should raise_error(Customerio::Client::ParamError)
|
|
542
|
-
end
|
|
543
|
-
end
|
|
544
|
-
end
|
|
545
|
-
|
|
546
|
-
describe "#devices" do
|
|
547
|
-
it "allows for the creation of a new device" do
|
|
548
|
-
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
|
549
|
-
to_return(status: 200, body: "", headers: {})
|
|
550
|
-
|
|
551
|
-
client.add_device(5, "androidDeviceID", "ios", {last_used: 1561235678})
|
|
552
|
-
client.add_device(5, "iosDeviceID", "android")
|
|
553
|
-
end
|
|
554
|
-
it "requires a valid customer_id when creating" do
|
|
555
|
-
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
|
556
|
-
to_return(status: 200, body: "", headers: {})
|
|
557
|
-
|
|
558
|
-
lambda { client.add_device("", "ios", "myDeviceID") }.should raise_error(Customerio::Client::ParamError)
|
|
559
|
-
lambda { client.add_device(nil, "ios", "myDeviceID", {last_used: 1561235678}) }.should raise_error(Customerio::Client::ParamError)
|
|
560
|
-
end
|
|
561
|
-
it "requires a valid token when creating" do
|
|
562
|
-
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
|
563
|
-
to_return(status: 200, body: "", headers: {})
|
|
564
|
-
|
|
565
|
-
lambda { client.add_device(5, "", "ios") }.should raise_error(Customerio::Client::ParamError)
|
|
566
|
-
lambda { client.add_device(5, nil, "ios", {last_used: 1561235678}) }.should raise_error(Customerio::Client::ParamError)
|
|
567
|
-
end
|
|
568
|
-
it "requires a valid platform when creating" do
|
|
569
|
-
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
|
570
|
-
to_return(status: 200, body: "", headers: {})
|
|
571
|
-
|
|
572
|
-
lambda { client.add_device(5, "token", "") }.should raise_error(Customerio::Client::ParamError)
|
|
573
|
-
lambda { client.add_device(5, "toke", nil, {last_used: 1561235678}) }.should raise_error(Customerio::Client::ParamError)
|
|
574
|
-
end
|
|
575
|
-
it "accepts a nil data param" do
|
|
576
|
-
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
|
577
|
-
to_return(status: 200, body: "", headers: {})
|
|
578
|
-
|
|
579
|
-
client.add_device(5, "ios", "myDeviceID", nil)
|
|
580
|
-
end
|
|
581
|
-
it "fails on invalid data param" do
|
|
582
|
-
stub_request(:put, api_uri('/api/v1/customers/5/devices')).
|
|
583
|
-
to_return(status: 200, body: "", headers: {})
|
|
584
|
-
|
|
585
|
-
lambda { client.add_device(5, "ios", "myDeviceID", 1000) }.should raise_error(Customerio::Client::ParamError)
|
|
586
|
-
end
|
|
587
|
-
it "supports deletion of devices by token" do
|
|
588
|
-
stub_request(:delete, api_uri('/api/v1/customers/5/devices/myDeviceID')).
|
|
589
|
-
to_return(status: 200, body: "", headers: {})
|
|
590
|
-
|
|
591
|
-
client.delete_device(5, "myDeviceID")
|
|
592
|
-
end
|
|
593
|
-
it "requires a valid customer_id when deleting" do
|
|
594
|
-
stub_request(:delete, api_uri('/api/v1/customers/5/devices/myDeviceID')).
|
|
595
|
-
to_return(status: 200, body: "", headers: {})
|
|
596
|
-
|
|
597
|
-
lambda { client.delete_device("", "myDeviceID") }.should raise_error(Customerio::Client::ParamError)
|
|
598
|
-
lambda { client.delete_device(nil, "myDeviceID") }.should raise_error(Customerio::Client::ParamError)
|
|
599
|
-
end
|
|
600
|
-
it "requires a valid device_id when deleting" do
|
|
601
|
-
stub_request(:delete, api_uri('/api/v1/customers/5/devices/myDeviceID')).
|
|
602
|
-
to_return(status: 200, body: "", headers: {})
|
|
603
|
-
|
|
604
|
-
lambda { client.delete_device(5, "") }.should raise_error(Customerio::Client::ParamError)
|
|
605
|
-
lambda { client.delete_device(5, nil) }.should raise_error(Customerio::Client::ParamError)
|
|
606
|
-
end
|
|
607
|
-
end
|
|
608
|
-
|
|
609
|
-
describe "#track_push_notification_event" do
|
|
610
|
-
attr_accessor :client, :attributes
|
|
611
|
-
|
|
612
|
-
before(:each) do
|
|
613
|
-
@client = Customerio::Client.new("SITE_ID", "API_KEY", :json => true)
|
|
614
|
-
@attributes = {
|
|
615
|
-
:delivery_id => 'foo',
|
|
616
|
-
:device_id => 'bar',
|
|
617
|
-
:timestamp => Time.now.to_i
|
|
618
|
-
}
|
|
619
|
-
end
|
|
620
|
-
|
|
621
|
-
it "sends a POST request to customer.io's /push/events endpoint" do
|
|
622
|
-
stub_request(:post, api_uri('/push/events')).
|
|
623
|
-
with(
|
|
624
|
-
:body => json(attributes.merge({
|
|
625
|
-
:event => 'opened'
|
|
626
|
-
})),
|
|
627
|
-
:headers => {
|
|
628
|
-
'Content-Type' => 'application/json'
|
|
629
|
-
}).
|
|
630
|
-
to_return(:status => 200, :body => "", :headers => {})
|
|
631
|
-
|
|
632
|
-
client.track_push_notification_event('opened', attributes)
|
|
633
|
-
end
|
|
634
|
-
|
|
635
|
-
it "should raise if event is invalid" do
|
|
636
|
-
stub_request(:post, api_uri('/push/events')).
|
|
637
|
-
to_return(:status => 200, :body => "", :headers => {})
|
|
638
|
-
|
|
639
|
-
expect {
|
|
640
|
-
client.track_push_notification_event('closed', attributes.merge({ :delivery_id => nil }))
|
|
641
|
-
}.to raise_error(Customerio::Client::ParamError, 'event_name must be one of opened, converted, or delivered')
|
|
642
|
-
end
|
|
643
|
-
|
|
644
|
-
it "should raise if delivery_id is invalid" do
|
|
645
|
-
stub_request(:post, api_uri('/push/events')).
|
|
646
|
-
to_return(:status => 200, :body => "", :headers => {})
|
|
647
|
-
|
|
648
|
-
expect {
|
|
649
|
-
client.track_push_notification_event('opened', attributes.merge({ :delivery_id => nil }))
|
|
650
|
-
}.to raise_error(Customerio::Client::ParamError, 'delivery_id must be a non-empty string')
|
|
651
|
-
|
|
652
|
-
expect {
|
|
653
|
-
client.track_push_notification_event('opened', attributes.merge({ :delivery_id => '' }))
|
|
654
|
-
}.to raise_error(Customerio::Client::ParamError, 'delivery_id must be a non-empty string')
|
|
655
|
-
end
|
|
656
|
-
|
|
657
|
-
it "should raise if device_id is invalid" do
|
|
658
|
-
stub_request(:post, api_uri('/push/events')).
|
|
659
|
-
to_return(:status => 200, :body => "", :headers => {})
|
|
660
|
-
|
|
661
|
-
expect {
|
|
662
|
-
client.track_push_notification_event('opened', attributes.merge({ :device_id => nil }))
|
|
663
|
-
}.to raise_error(Customerio::Client::ParamError, 'device_id must be a non-empty string')
|
|
664
|
-
|
|
665
|
-
expect {
|
|
666
|
-
client.track_push_notification_event('opened', attributes.merge({ :device_id => '' }))
|
|
667
|
-
}.to raise_error(Customerio::Client::ParamError, 'device_id must be a non-empty string')
|
|
668
|
-
end
|
|
669
|
-
|
|
670
|
-
it "should raise if timestamp is invalid" do
|
|
671
|
-
stub_request(:post, api_uri('/push/events')).
|
|
672
|
-
to_return(:status => 200, :body => "", :headers => {})
|
|
673
|
-
|
|
674
|
-
expect {
|
|
675
|
-
client.track_push_notification_event('opened', attributes.merge({ :timestamp => nil }))
|
|
676
|
-
}.to raise_error(Customerio::Client::ParamError, 'timestamp must be a valid timestamp')
|
|
677
|
-
|
|
678
|
-
expect {
|
|
679
|
-
client.track_push_notification_event('opened', attributes.merge({ :timestamp => 999999999 }))
|
|
680
|
-
}.to raise_error(Customerio::Client::ParamError, 'timestamp must be a valid timestamp')
|
|
681
|
-
|
|
682
|
-
expect {
|
|
683
|
-
client.track_push_notification_event('opened', attributes.merge({ :timestamp => 100000000000 }))
|
|
684
|
-
}.to raise_error(Customerio::Client::ParamError, 'timestamp must be a valid timestamp')
|
|
685
|
-
end
|
|
686
|
-
end
|
|
687
|
-
|
|
688
|
-
describe "#merge_customers" do
|
|
689
|
-
before(:each) do
|
|
690
|
-
@client = Customerio::Client.new("SITE_ID", "API_KEY", :json => true)
|
|
691
|
-
end
|
|
692
|
-
|
|
693
|
-
it "should raise validation errors on merge params" do
|
|
694
|
-
expect {
|
|
695
|
-
client.merge_customers("", "id1", Customerio::IdentifierType::ID, "id2")
|
|
696
|
-
}.to raise_error(Customerio::Client::ParamError, 'invalid primary_id_type')
|
|
697
|
-
|
|
698
|
-
expect {
|
|
699
|
-
client.merge_customers(Customerio::IdentifierType::EMAIL, "", Customerio::IdentifierType::ID, "id2")
|
|
700
|
-
}.to raise_error(Customerio::Client::ParamError, 'primary_id must be a non-empty string')
|
|
701
|
-
|
|
702
|
-
expect {
|
|
703
|
-
client.merge_customers(Customerio::IdentifierType::CIOID, "id1", "", "id2")
|
|
704
|
-
}.to raise_error(Customerio::Client::ParamError, 'invalid secondary_id_type')
|
|
705
|
-
|
|
706
|
-
expect {
|
|
707
|
-
client.merge_customers(Customerio::IdentifierType::ID, "id1", Customerio::IdentifierType::ID, "")
|
|
708
|
-
}.to raise_error(Customerio::Client::ParamError, 'secondary_id must be a non-empty string')
|
|
709
|
-
end
|
|
710
|
-
|
|
711
|
-
it "requires a valid customer_id when creating" do
|
|
712
|
-
stub_request(:post, api_uri('/api/v1/merge_customers')).
|
|
713
|
-
to_return(status: 200, body: "", headers: {})
|
|
714
|
-
|
|
715
|
-
client.merge_customers(Customerio::IdentifierType::ID, "ID1", Customerio::IdentifierType::EMAIL, "hello@company.com")
|
|
716
|
-
end
|
|
717
|
-
end
|
|
718
|
-
end
|