liveqa 1.4.6 → 1.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/.travis.yml +1 -0
  4. data/README.md +94 -7
  5. data/lib/liveqa/api_operation/delete.rb +38 -0
  6. data/lib/liveqa/api_resource.rb +7 -6
  7. data/lib/liveqa/async_handlers/base.rb +1 -3
  8. data/lib/liveqa/config.rb +35 -11
  9. data/lib/liveqa/event.rb +4 -10
  10. data/lib/liveqa/group.rb +14 -0
  11. data/lib/liveqa/identity.rb +16 -0
  12. data/lib/liveqa/liveqa_object.rb +48 -8
  13. data/lib/liveqa/message.rb +31 -10
  14. data/lib/liveqa/plugins/rack/middleware.rb +50 -36
  15. data/lib/liveqa/plugins/rails/data.rb +19 -0
  16. data/lib/liveqa/plugins/rails/middleware_data.rb +2 -18
  17. data/lib/liveqa/plugins/sidekiq/client_middleware.rb +1 -1
  18. data/lib/liveqa/plugins/sidekiq/server_middleware.rb +2 -2
  19. data/lib/liveqa/plugins.rb +1 -0
  20. data/lib/liveqa/request.rb +2 -0
  21. data/lib/liveqa/store.rb +1 -1
  22. data/lib/liveqa/util.rb +81 -1
  23. data/lib/liveqa/version.rb +1 -1
  24. data/lib/liveqa/watcher.rb +15 -0
  25. data/lib/liveqa.rb +82 -4
  26. data/spec/lib/liveqa/api_resource_spec.rb +109 -0
  27. data/spec/lib/liveqa/async_handlers/base_spec.rb +13 -3
  28. data/spec/lib/liveqa/config_spec.rb +8 -6
  29. data/spec/lib/liveqa/event_spec.rb +2 -23
  30. data/spec/lib/liveqa/group_spec.rb +15 -0
  31. data/spec/lib/liveqa/identity_spec.rb +15 -0
  32. data/spec/lib/liveqa/liveqa_object_spec.rb +53 -2
  33. data/spec/lib/liveqa/message_spec.rb +75 -8
  34. data/spec/lib/liveqa/plugins/rack/middleware_spec.rb +8 -2
  35. data/spec/lib/liveqa/plugins/rails/data_spec.rb +22 -0
  36. data/spec/lib/liveqa/plugins/rails/middleware_data_spec.rb +2 -23
  37. data/spec/lib/liveqa/plugins/sidekiq/server_middleware_spec.rb +6 -12
  38. data/spec/lib/liveqa/util_spec.rb +40 -0
  39. data/spec/lib/liveqa/watcher_spec.rb +25 -0
  40. data/spec/lib/liveqa_spec.rb +88 -5
  41. data/spec/spec_helper.rb +3 -1
  42. metadata +17 -2
@@ -5,12 +5,8 @@ module LiveQA
5
5
 
6
6
  class << self
7
7
 
8
- def store_data(request)
9
- LiveQA::Store.bulk_set(
10
- environement: ::Rails.env
11
- )
12
- store_request_data(request)
13
- store_framework
8
+ def store_data(request = nil)
9
+ store_request_data(request) if request
14
10
  end
15
11
 
16
12
  private
@@ -24,18 +20,6 @@ module LiveQA
24
20
  )
25
21
  end
26
22
 
27
- def store_framework
28
- stack = LiveQA::Store.get(:stack) || []
29
-
30
- LiveQA::Store.set(
31
- :stack,
32
- stack.push(
33
- name: 'rails',
34
- version: ::Rails.version
35
- )
36
- )
37
- end
38
-
39
23
  end
40
24
 
41
25
  end
@@ -9,7 +9,7 @@ module LiveQA
9
9
  class ClientMiddleware
10
10
 
11
11
  def call(_worker_class, job, _queue, _redis_pool)
12
- job['liveqa_store'] = LiveQA::Store.store
12
+ job['liveqa_session_tracker_id'] = LiveQA::Store.store[:session_tracker_id]
13
13
  yield
14
14
  end
15
15
 
@@ -9,7 +9,7 @@ module LiveQA
9
9
  class ServerMiddleware
10
10
 
11
11
  def call(_worker, job, _queue)
12
- LiveQA::Store.load_from_hash(job['liveqa_store'])
12
+ LiveQA::Store.set(:session_tracker_id, job['liveqa_session_tracker_id'] || SecureRandom.uuid)
13
13
  store_worker_data(job)
14
14
  yield
15
15
  ensure
@@ -36,7 +36,7 @@ module LiveQA
36
36
  end
37
37
 
38
38
  def convert_to_iso8601(int_time)
39
- Time.at(int_time).utc.iso8601
39
+ Time.at(int_time).utc.iso8601(3)
40
40
  rescue
41
41
  nil
42
42
  end
@@ -7,6 +7,7 @@ if defined?(Rack)
7
7
  if defined?(Rails)
8
8
  require 'liveqa/plugins/rails/railtie'
9
9
  require 'liveqa/plugins/rails/middleware_data'
10
+ require 'liveqa/plugins/rails/data'
10
11
  end
11
12
  end
12
13
 
@@ -60,6 +60,7 @@ module LiveQA
60
60
  def put
61
61
  @request = Net::HTTP::Put.new(uri.path)
62
62
 
63
+ set_header
63
64
  request.body = params[:payload]
64
65
 
65
66
  handle_request
@@ -76,6 +77,7 @@ module LiveQA
76
77
  def delete
77
78
  @request = Net::HTTP::Delete.new(uri.path)
78
79
 
80
+ set_header
79
81
  request.body = params[:payload]
80
82
 
81
83
  handle_request
data/lib/liveqa/store.rb CHANGED
@@ -2,7 +2,7 @@ module LiveQA
2
2
  ##
3
3
  # == LiveQA \Store
4
4
  #
5
- # Store environement data
5
+ # Store environment data
6
6
  #
7
7
  class Store
8
8
  class << self
data/lib/liveqa/util.rb CHANGED
@@ -3,7 +3,30 @@ module LiveQA
3
3
  class << self
4
4
 
5
5
  DATE_FORMAT = '%Y/%m/%d'.freeze
6
- OBFUSCATED = '[HIDDEN]'.freeze
6
+ OBFUSCATED = '[HIDDEN]'.freeze
7
+ DEFAULT_OBJECT_DEF = %w[id name].freeze
8
+
9
+ ##
10
+ # Remove keys from a Hash
11
+ #
12
+ # @param [Hash] to be excepted
13
+ # @param [List[String]] to be excepted
14
+ #
15
+ # @return [Hash]
16
+ def except_keys(hash, *keys)
17
+ hash.dup.delete_if { |(key, _value)| keys.include?(key) }
18
+ end
19
+
20
+ ##
21
+ # Convert string to camelize
22
+ #
23
+ # @param [String]
24
+ #
25
+ # @example
26
+ # camelize('my_model') => 'MyModel'
27
+ def camelize(string)
28
+ string.split('_').map(&:capitalize).join
29
+ end
7
30
 
8
31
  ##
9
32
  # Remove nil value from hash
@@ -128,6 +151,38 @@ module LiveQA
128
151
  end
129
152
  end
130
153
 
154
+ ##
155
+ # Convert object into Hash
156
+ #
157
+ # @params [Objects]
158
+ #
159
+ # @return [Hash]
160
+ def properties(*args)
161
+ params = extract_params!(args)
162
+
163
+ attributes = params.each_with_object({}) do |(key, value), hash|
164
+ hash[key] = extract_object(value)
165
+ end
166
+
167
+ attributes.merge(
168
+ args.each_with_object({}) do |object, hash|
169
+ key = object.class.name.downcase
170
+ next if key.nil?
171
+
172
+ hash[key] = extract_object(object)
173
+ end
174
+ )
175
+ end
176
+
177
+ ##
178
+ # Parse JSON without raise
179
+ #
180
+ def safe_json_parse(data)
181
+ JSON.parse(data.to_s)
182
+ rescue JSON::ParserError
183
+ {}
184
+ end
185
+
131
186
  private
132
187
 
133
188
  def deep_transform_keys_in_object(object, &block)
@@ -143,6 +198,31 @@ module LiveQA
143
198
  end
144
199
  end
145
200
 
201
+ def extract_object(object, custom_object_properties = LiveQA.configurations.custom_object_properties)
202
+ return unless object
203
+
204
+ object_name = object.class.name.downcase
205
+
206
+ columns =
207
+ custom_object_properties[object_name.to_sym] ||
208
+ custom_object_properties[object_name.to_s] ||
209
+ DEFAULT_OBJECT_DEF
210
+
211
+ params = columns.each_with_object({}) do |column, attributes|
212
+ attributes[column.to_s] = object.send(column) if object.respond_to?(column)
213
+ end
214
+
215
+ params.empty? ? object : params
216
+ end
217
+
218
+ def extract_params!(args)
219
+ if args.last.is_a?(Hash) && args.last.instance_of?(Hash)
220
+ args.pop
221
+ else
222
+ {}
223
+ end
224
+ end
225
+
146
226
  end
147
227
  end
148
228
  end
@@ -1,3 +1,3 @@
1
1
  module LiveQA # :nodoc:
2
- VERSION = '1.4.6'.freeze
2
+ VERSION = '1.8.3'.freeze
3
3
  end
@@ -0,0 +1,15 @@
1
+ module LiveQA
2
+ ##
3
+ # == LiveQA \Watcher
4
+ #
5
+ # Create and update groups
6
+ #
7
+ # @example: Usage
8
+ #
9
+ # request = LiveQA::Watcher.create(template_flow: 'My Flow', expected_times: 42) #=> #<LiveQA::Response...>
10
+ #
11
+ class Watcher < APIResource
12
+ include LiveQA::APIOperation::Save
13
+ include LiveQA::APIOperation::Delete
14
+ end
15
+ end
data/lib/liveqa.rb CHANGED
@@ -3,6 +3,8 @@ require 'securerandom'
3
3
  require 'net/http'
4
4
  require 'ostruct'
5
5
  require 'json'
6
+ require 'time'
7
+ require 'cgi'
6
8
 
7
9
  # Async
8
10
  require 'liveqa/async_handlers/base'
@@ -21,9 +23,13 @@ require 'liveqa/message'
21
23
 
22
24
  # Operations
23
25
  require 'liveqa/api_operation/save'
26
+ require 'liveqa/api_operation/delete'
24
27
 
25
28
  # Resources
26
29
  require 'liveqa/event'
30
+ require 'liveqa/group'
31
+ require 'liveqa/identity'
32
+ require 'liveqa/watcher'
27
33
 
28
34
  # Plugins
29
35
  require 'liveqa/plugins'
@@ -42,7 +48,9 @@ module LiveQA
42
48
  #
43
49
  # @example Default configuration
44
50
  # LiveQA.configure do |config|
45
- # config.api_key = 'your-api-key'
51
+ # config.account_token = 'acc_xx'
52
+ # config.space_name = 'LiveQA'
53
+ # config.environment_name = 'production'
46
54
  # end
47
55
  def configure
48
56
  yield @configurations = LiveQA::Config.new
@@ -54,7 +62,6 @@ module LiveQA
54
62
  # Send a track event to the server
55
63
  #
56
64
  # @param [String] event name
57
- # @param [String] user id from your database
58
65
  # @param [Hash] payload to be send
59
66
  # @param [Hash] options for the request
60
67
  #
@@ -64,8 +71,9 @@ module LiveQA
64
71
 
65
72
  payload[:type] = 'track'
66
73
  payload[:name] = name
74
+ LiveQA::Plugins::Rails::Data.store_data if defined?(LiveQA::Plugins::Rails::Data)
67
75
 
68
- payload = Event.build_payload(payload)
76
+ payload = Message.extended.merge(payload)
69
77
 
70
78
  if configurations.async_handler
71
79
  return configurations.async_handler.enqueue('LiveQA::Event', 'create', payload, request_options)
@@ -89,8 +97,9 @@ module LiveQA
89
97
 
90
98
  payload[:type] = 'identify'
91
99
  payload[:user_id] = user_id
100
+ LiveQA::Plugins::Rails::Data.store_data if defined?(LiveQA::Plugins::Rails::Data)
92
101
 
93
- payload = Event.build_payload(payload)
102
+ payload = Message.extended.merge(payload)
94
103
 
95
104
  if configurations.async_handler
96
105
  return configurations.async_handler.enqueue('LiveQA::Event', 'create', payload, request_options)
@@ -101,5 +110,74 @@ module LiveQA
101
110
  event.successful?
102
111
  end
103
112
 
113
+ ##
114
+ # Send a create/update for a group
115
+ #
116
+ # @param [String] group id from your database
117
+ # @param [Hash] payload to be send
118
+ # @param [Hash] options for the request
119
+ #
120
+ # @return [LiveQA::Object] response from the server
121
+ def set_group(group_id, payload = {}, request_options = {})
122
+ return true unless configurations.enabled
123
+
124
+ payload = Message.base.merge(payload)
125
+
126
+ if configurations.async_handler
127
+ return configurations.async_handler.enqueue('LiveQA::Group', 'update', group_id, payload, request_options)
128
+ end
129
+
130
+ group = Group.update(group_id, payload, request_options)
131
+
132
+ group.successful?
133
+ end
134
+
135
+ ##
136
+ # Send a create/update for an identity
137
+ #
138
+ # @param [String] user id from your database
139
+ # @param [Hash] payload to be send
140
+ # @param [Hash] options for the request
141
+ #
142
+ # @return [LiveQA::Object] response from the server
143
+ def set_identity(user_id, payload = {}, request_options = {})
144
+ return true unless configurations.enabled
145
+
146
+ payload = Message.base.merge(payload)
147
+
148
+ if configurations.async_handler
149
+ return configurations.async_handler.enqueue('LiveQA::Identity', 'update', user_id, payload, request_options)
150
+ end
151
+
152
+ identity = Identity.update(user_id, payload, request_options)
153
+
154
+ identity.successful?
155
+ end
156
+
157
+ ##
158
+ # Send a create a watcher
159
+ #
160
+ # @param [String|Integer] template flow name or id
161
+ # @param [Hash] payload to be send
162
+ # @param [Hash] options for the request
163
+ #
164
+ # @return [LiveQA::Object] response from the server
165
+ def watch(id_or_name, payload = {}, request_options = {})
166
+ return true unless configurations.enabled
167
+
168
+ payload[:template_flow] = id_or_name
169
+ payload = Message.base.merge(payload)
170
+
171
+ payload.delete(:session_tracker_id) if payload.delete(:without_session)
172
+
173
+ if configurations.async_handler
174
+ return configurations.async_handler.enqueue('LiveQA::Watcher', 'create', payload, request_options)
175
+ end
176
+
177
+ watcher = Watcher.create(payload, request_options)
178
+
179
+ watcher.successful?
180
+ end
181
+
104
182
  end
105
183
  end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+
3
+ describe LiveQA::APIResource do
4
+
5
+ describe '#request' do
6
+ subject(:resource) { LiveQA::APIResource.request(:post, '/test') }
7
+
8
+ context 'valid request' do
9
+ let(:response) { double('response', code: '200', code_type: Net::HTTPOK, body: {}.to_json) }
10
+
11
+ context 'default payload' do
12
+ let(:expected_payload) {{
13
+ method: :post,
14
+ url: 'http://localhost:4003/test',
15
+ payload: '{}',
16
+ use_ssl: false,
17
+ headers: {
18
+ accept: 'application/json',
19
+ content_type: 'application/json',
20
+ x_account_token: 'acc_xx',
21
+ x_space_name: 'LiveQA',
22
+ x_environment_name: 'test'
23
+ }
24
+ }}
25
+
26
+ after { resource }
27
+
28
+ it { expect(LiveQA::Request).to receive(:execute).with(expected_payload).and_return(response) }
29
+ end
30
+
31
+ context 'with body and post' do
32
+ let(:expected_payload) {{
33
+ method: :post,
34
+ url: 'http://localhost:4003/test',
35
+ payload: "{\"test\":true}",
36
+ use_ssl: false,
37
+ headers: {
38
+ accept: 'application/json',
39
+ content_type: 'application/json',
40
+ x_account_token: 'acc_xx',
41
+ x_space_name: 'LiveQA',
42
+ x_environment_name: 'test'
43
+ }
44
+ }}
45
+
46
+ after { LiveQA::APIResource.request(:post, '/test', { test: true }) }
47
+
48
+ it { expect(LiveQA::Request).to receive(:execute).with(expected_payload).and_return(response) }
49
+ end
50
+
51
+ context 'with body and get' do
52
+ let(:expected_payload) {{
53
+ method: :get,
54
+ url: 'http://localhost:4003/test?test=true',
55
+ payload: "{\"test\":true}",
56
+ use_ssl: false,
57
+ headers: {
58
+ accept: 'application/json',
59
+ content_type: 'application/json',
60
+ x_account_token: 'acc_xx',
61
+ x_space_name: 'LiveQA',
62
+ x_environment_name: 'test'
63
+ }
64
+ }}
65
+
66
+ after { LiveQA::APIResource.request(:get, '/test', { test: true }) }
67
+
68
+ it { expect(LiveQA::Request).to receive(:execute).with(expected_payload).and_return(response) }
69
+ end
70
+
71
+ context 'with overwrite headers tokens' do
72
+ let(:expected_payload) {{
73
+ method: :post,
74
+ url: 'http://localhost:4003/test',
75
+ payload: '{}',
76
+ use_ssl: false,
77
+ headers: {
78
+ accept: 'application/json',
79
+ content_type: 'application/json',
80
+ x_account_token: 'acc_42',
81
+ x_space_name: 'MySpace',
82
+ x_environment_name: 'staging'
83
+ }
84
+ }}
85
+
86
+ after { LiveQA::APIResource.request(:post, '/test', {}, account_token: 'acc_42', space_name: 'MySpace', environment_name: 'staging') }
87
+
88
+ it { expect(LiveQA::Request).to receive(:execute).with(expected_payload).and_return(response) }
89
+ end
90
+ end
91
+
92
+ context 'with errors' do
93
+ before { allow(LiveQA::Request).to receive(:execute).and_raise(LiveQA::RequestError.new(response)) }
94
+
95
+ context 'with Net::HTTPUnprocessableEntity' do
96
+ let(:response) { double('response', code: '422', code_type: Net::HTTPUnprocessableEntity, body: {}.to_json, message: 'failed') }
97
+
98
+ it { expect { resource }.to_not raise_error }
99
+ end
100
+
101
+ context 'with Net::HTTPBadRequest' do
102
+ let(:response) { double('response', code: '400', code_type: Net::HTTPBadRequest, body: {}.to_json, message: 'failed') }
103
+
104
+ it { expect { resource }.to_not raise_error }
105
+ end
106
+ end
107
+ end
108
+
109
+ end
@@ -10,10 +10,20 @@ describe LiveQA::AsyncHandlers::Base do
10
10
  end
11
11
 
12
12
  describe 'execute' do
13
- let(:params) { ['LiveQA::Event', 'create', { test: true }] }
13
+ context 'default params' do
14
+ let(:params) { ['LiveQA::Event', 'create', { test: true }] }
14
15
 
15
- after { base.execute(params) }
16
+ after { base.execute(params) }
16
17
 
17
- it { expect(LiveQA::Event).to receive(:create).with({ test: true }, nil) }
18
+ it { expect(LiveQA::Event).to receive(:create).with({ test: true }) }
19
+ end
20
+
21
+ context 'more params params' do
22
+ let(:params) { ['LiveQA::Group', 'update', 42, { test: true }, { no_ssl: true }] }
23
+
24
+ after { base.execute(params) }
25
+
26
+ it { expect(LiveQA::Group).to receive(:update).with(42, { test: true }, { no_ssl: true }) }
27
+ end
18
28
  end
19
29
  end
@@ -4,30 +4,32 @@ describe LiveQA::Config do
4
4
  subject(:config) { LiveQA::Config.new(params) }
5
5
 
6
6
  describe '#initialize' do
7
- let(:params) {{ api_key: SecureRandom.hex }}
7
+ let(:params) {{ account_token: 'acc_xx', space_name: 'LiveQA', environment_name: 'test' }}
8
8
 
9
9
  it { expect(config.valid!).to be_truthy }
10
10
 
11
- %i[api_key api_host api_version].each do |field|
11
+ %i[account_token environment_name api_host api_version].each do |field|
12
12
  context "validate #{field}" do
13
- let(:params) {{ api_key: 'api-key', api_host: 'host', api_version: 'v1' }.merge(field => '')}
13
+ let(:params) {{ account_token: 'acc_xx', space_name: 'LiveQA', environment_name: 'test', api_host: 'host', api_version: 'v1' }.merge(field => '')}
14
14
 
15
15
  it { expect { config.valid! }.to raise_error(LiveQA::ConfigurationError, "#{field} can't be blank") }
16
16
  end
17
17
  end
18
18
 
19
19
  context 'format obfuscated_fields' do
20
- let(:params) {{ api_key: SecureRandom.hex, obfuscated_fields: %i[another_password password_confirmation] }}
20
+ let(:params) {{ account_token: 'acc_xx', space_name: 'LiveQA', environment_name: 'test', obfuscated_fields: %i[another_password password_confirmation] }}
21
21
 
22
22
  before { config.valid! }
23
23
 
24
- it { expect(config.obfuscated_fields).to match_array(%w[another_password password_confirmation password access_token api_key ccv credit_card_number cvv secret secret_token token]) }
24
+ it { expect(config.obfuscated_fields).to match_array(%w[another_password password_confirmation password access_token api_key authenticity_token ccv credit_card_number cvv secret secret_token token]) }
25
25
  end
26
26
 
27
27
  context 'async_handler' do
28
28
  context 'sidekiq' do
29
29
  let(:params) {{
30
- api_key: SecureRandom.hex,
30
+ account_token: 'acc_xx',
31
+ space_name: 'LiveQA',
32
+ environment_name: 'test',
31
33
  async_handler: :sidekiq
32
34
  }}
33
35
  before { config.valid! }
@@ -2,35 +2,14 @@ require 'spec_helper'
2
2
 
3
3
  describe LiveQA::Event do
4
4
 
5
- describe '.build_payload' do
6
- before { LiveQA::Store.set(:tracker_id, '41') }
7
-
8
- let(:expected) {{
9
- library: {
10
- name: "liveqa",
11
- language: "ruby",
12
- version: kind_of(String)
13
- },
14
- server: {
15
- host: kind_of(String),
16
- pid: kind_of(Numeric)
17
- },
18
- message_id: kind_of(String),
19
- timestamp: kind_of(String),
20
- tracker_id: '42',
21
- session_tracker_id: kind_of(String)
22
- }}
23
-
24
- it { expect(LiveQA::Event.build_payload(tracker_id: '42')).to match(expected) }
25
- end
26
-
27
5
  describe '.create' do
28
- let(:response) { double('LiveQA::Request', body: '') }
6
+ let(:response) { double('LiveQA::Request', body: "{\"object\":\"event\",\"id\":41}") }
29
7
  before { expect(LiveQA::Request).to receive(:execute).and_return(response) }
30
8
 
31
9
  subject(:create) { LiveQA::Event.create(user_id: 42) }
32
10
 
33
11
  it { is_expected.to be_successful }
12
+ it { expect(create.id).to eq(41) }
34
13
  end
35
14
 
36
15
  end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe LiveQA::Group do
4
+
5
+ describe '#update' do
6
+ let(:response) { double('LiveQA::Request', body: "{\"object\":\"group\",\"id\":3,\"externalId\":\"41df8a48a68cb7c94e119ef7f1380537\",\"rawData\":{\"name\":\"Lubowitz, Cartwright and Davis\",\"email\":\"kenya_parker@batz.info\",\"plan\":\"premium\",\"address\":{\"street\":\"19222 Keyshawn Mountain\",\"city\":\"Rogahnmouth\",\"state\":\"Hawaii\",\"postal_code\":\"98441-4908\",\"country\":\"Singapore\"}}}") }
7
+ before { expect(LiveQA::Request).to receive(:execute).and_return(response) }
8
+
9
+ subject(:update) { LiveQA::Group.update('41df8a48a68cb7c94e119ef7f1380537', properties: { name: 'Lubowitz, Cartwright and Davis' }) }
10
+
11
+ it { is_expected.to be_successful }
12
+ it { expect(update.external_id).to eq('41df8a48a68cb7c94e119ef7f1380537') }
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe LiveQA::Identity do
4
+
5
+ describe '#update' do
6
+ let(:response) { double('LiveQA::Request', body: "{\"object\":\"identity\",\"id\":1,\"externalId\":\"8b5439f2bc0bc5bc2b80817f29477f0d\",\"trackerIds\":[],\"rawData\":{\"name\":\"Runte, Macejkovic and Reinger\",\"email\":\"hardy@abernathy.com\",\"plan\":\"premium\",\"address\":{\"street\":\"680 Collins Branch\",\"city\":\"Holdenview\",\"state\":\"Alabama\",\"postal_code\":\"51094-2637\",\"country\":\"America\"}},\"devices\":{\"object\":\"list\",\"data\":[{\"object\":\"device\",\"bot\":false,\"botName\":null,\"brand\":null,\"browserName\":\"chrome\",\"fullVersion\":\"62.0.3202.94\",\"known\":true,\"name\":null,\"osFullVersion\":\"10.12.5\",\"osName\":\"mac\",\"osVersion\":\"10\",\"type\":\"desktop\",\"version\":\"62\",\"usedLastAt\":null}]}}") }
7
+ before { expect(LiveQA::Request).to receive(:execute).and_return(response) }
8
+
9
+ subject(:update) { LiveQA::Identity.update('8b5439f2bc0bc5bc2b80817f29477f0d', properties: { name: 'Runte, Macejkovic and Reinger' }) }
10
+
11
+ it { is_expected.to be_successful }
12
+ it { expect(update.external_id).to eq('8b5439f2bc0bc5bc2b80817f29477f0d') }
13
+ end
14
+
15
+ end
@@ -5,7 +5,24 @@ describe LiveQA::LiveQAObject do
5
5
  let(:klass) { Class.new(LiveQA::LiveQAObject) }
6
6
  subject(:instance) { klass.new(id: 42, name: 'test', test: true) }
7
7
 
8
- let(:api_response) { '' }
8
+ let(:api_response) {{
9
+ object: 'event',
10
+ id: 42,
11
+ other: 'other test'
12
+ }}
13
+
14
+ let(:api_responses) {{
15
+ object: 'list',
16
+ currentPage: 10,
17
+ data: [{
18
+ object: 'group',
19
+ id: 42,
20
+ other: 'other test'
21
+ }],
22
+ links: {
23
+ self: 'http://www.liveqa.io/test'
24
+ }
25
+ }}
9
26
 
10
27
  describe 'add attribute accessors' do
11
28
  it { expect(instance.id).to eq(42) }
@@ -62,10 +79,44 @@ describe LiveQA::LiveQAObject do
62
79
 
63
80
  describe '.initialize_from' do
64
81
  context 'with single object' do
65
- subject(:instance) { klass.initialize_from(api_response) }
82
+ subject(:instance) { klass.initialize_from(api_response.to_json) }
66
83
 
67
84
  it { is_expected.to be_successful }
85
+ it { expect(instance.id).to eq(42) }
86
+ it { expect(instance.other).to eq('other test') }
87
+ it { expect { instance.name }.to raise_error(NameError) }
68
88
  end
89
+
90
+ context 'with array' do
91
+ subject(:instance) { klass.initialize_from(api_responses.to_json) }
92
+
93
+ it { is_expected.to be_successful }
94
+ it { expect(instance.data.size).to eq(1) }
95
+ it { expect(instance.data.first).to be_a(LiveQA::Group) }
96
+ it { expect(instance.current_page).to eq(10) }
97
+ it { expect(instance.links[:self]).to eq('http://www.liveqa.io/test') }
98
+ end
99
+
100
+ context 'with empty string' do
101
+ subject(:instance) { klass.initialize_from('') }
102
+
103
+ it { is_expected.to be_successful }
104
+ end
105
+
106
+ context 'with nil' do
107
+ subject(:instance) { klass.initialize_from(nil) }
108
+
109
+ it { is_expected.to be_successful }
110
+ end
111
+ end
112
+
113
+ describe '#update_from' do
114
+ before { instance.update_from(api_response) }
115
+
116
+ it { is_expected.to be_successful }
117
+ it { expect(instance.id).to eq(42) }
118
+ it { expect(instance.other).to eq('other test') }
119
+ it { expect { instance.name }.to raise_error(NameError) }
69
120
  end
70
121
 
71
122