netsuite 0.8.5 → 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/main.yml +20 -0
  3. data/.ruby-version +1 -1
  4. data/.tool-versions +1 -0
  5. data/Gemfile +1 -5
  6. data/HISTORY.md +32 -0
  7. data/README.md +48 -21
  8. data/Rakefile +1 -1
  9. data/lib/netsuite/configuration.rb +21 -4
  10. data/lib/netsuite/records/accounting_period.rb +2 -2
  11. data/lib/netsuite/records/assembly_unbuild.rb +1 -3
  12. data/lib/netsuite/records/classification.rb +4 -1
  13. data/lib/netsuite/records/contact.rb +1 -1
  14. data/lib/netsuite/records/cost_category.rb +28 -0
  15. data/lib/netsuite/records/credit_memo.rb +1 -1
  16. data/lib/netsuite/records/currency_rate.rb +1 -1
  17. data/lib/netsuite/records/custom_field_list.rb +9 -3
  18. data/lib/netsuite/records/custom_record.rb +1 -1
  19. data/lib/netsuite/records/customer.rb +2 -1
  20. data/lib/netsuite/records/customer_credit_cards.rb +36 -0
  21. data/lib/netsuite/records/customer_credit_cards_list.rb +10 -0
  22. data/lib/netsuite/records/customer_deposit.rb +5 -5
  23. data/lib/netsuite/records/customer_payment.rb +6 -2
  24. data/lib/netsuite/records/customer_payment_credit.rb +17 -0
  25. data/lib/netsuite/records/customer_payment_credit_list.rb +12 -0
  26. data/lib/netsuite/records/employee.rb +1 -1
  27. data/lib/netsuite/records/estimate.rb +42 -0
  28. data/lib/netsuite/records/estimate_item.rb +40 -0
  29. data/lib/netsuite/records/estimate_item_list.rb +11 -0
  30. data/lib/netsuite/records/inventory_item.rb +62 -1
  31. data/lib/netsuite/records/invoice.rb +97 -4
  32. data/lib/netsuite/records/invoice_item.rb +1 -1
  33. data/lib/netsuite/records/item_fulfillment.rb +1 -1
  34. data/lib/netsuite/records/item_fulfillment_item.rb +1 -1
  35. data/lib/netsuite/records/item_receipt_item.rb +1 -1
  36. data/lib/netsuite/records/member_list.rb +0 -2
  37. data/lib/netsuite/records/non_inventory_purchase_item.rb +1 -1
  38. data/lib/netsuite/records/non_inventory_resale_item.rb +2 -1
  39. data/lib/netsuite/records/non_inventory_sale_item.rb +1 -1
  40. data/lib/netsuite/records/opportunity.rb +2 -2
  41. data/lib/netsuite/records/partner.rb +7 -5
  42. data/lib/netsuite/records/phone_call.rb +1 -1
  43. data/lib/netsuite/records/serialized_assembly_item.rb +3 -2
  44. data/lib/netsuite/records/service_resale_item.rb +2 -2
  45. data/lib/netsuite/records/service_sale_item.rb +1 -1
  46. data/lib/netsuite/records/transfer_order_item.rb +1 -1
  47. data/lib/netsuite/records/vendor.rb +6 -5
  48. data/lib/netsuite/records/vendor_currency.rb +26 -0
  49. data/lib/netsuite/records/vendor_currency_list.rb +9 -0
  50. data/lib/netsuite/support/fields.rb +17 -0
  51. data/lib/netsuite/support/records.rb +1 -1
  52. data/lib/netsuite/support/search_result.rb +23 -4
  53. data/lib/netsuite/utilities.rb +2 -1
  54. data/lib/netsuite/version.rb +1 -1
  55. data/lib/netsuite.rb +10 -0
  56. data/netsuite.gemspec +5 -3
  57. data/spec/netsuite/actions/search_spec.rb +22 -0
  58. data/spec/netsuite/configuration_spec.rb +93 -6
  59. data/spec/netsuite/records/basic_record_spec.rb +8 -1
  60. data/spec/netsuite/records/classification_spec.rb +10 -1
  61. data/spec/netsuite/records/cost_category_spec.rb +105 -0
  62. data/spec/netsuite/records/custom_field_list_spec.rb +46 -6
  63. data/spec/netsuite/records/custom_record_spec.rb +1 -1
  64. data/spec/netsuite/records/customer_credit_cards_list_spec.rb +23 -0
  65. data/spec/netsuite/records/customer_payment_credit_list_spec.rb +26 -0
  66. data/spec/netsuite/records/customer_payment_spec.rb +1 -6
  67. data/spec/netsuite/records/customer_spec.rb +22 -1
  68. data/spec/netsuite/records/employee_spec.rb +2 -2
  69. data/spec/netsuite/records/estimate_item_list_spec.rb +26 -0
  70. data/spec/netsuite/records/estimate_item_spec.rb +40 -0
  71. data/spec/netsuite/records/estimate_spec.rb +216 -0
  72. data/spec/netsuite/records/inventory_item_spec.rb +65 -0
  73. data/spec/netsuite/records/invoice_spec.rb +94 -0
  74. data/spec/netsuite/records/non_inventory_resale_item_spec.rb +165 -0
  75. data/spec/netsuite/records/partner_spec.rb +143 -0
  76. data/spec/netsuite/records/service_resale_item_spec.rb +134 -0
  77. data/spec/netsuite/records/vendor_spec.rb +1 -1
  78. data/spec/netsuite/support/fields_spec.rb +36 -1
  79. data/spec/support/fixtures/custom_fields/multi_select.xml +47 -0
  80. data/spec/support/fixtures/search/saved_search_item.xml +55 -0
  81. data/spec/support/fixtures/search/saved_search_joined_custom_customer.xml +15 -1
  82. data/spec/support/search_only_field_matcher.rb +7 -0
  83. metadata +68 -12
  84. data/circle.yml +0 -17
@@ -168,9 +168,31 @@ describe NetSuite::Actions::Search do
168
168
 
169
169
  expect(search.results.size).to eq(2)
170
170
  expect(search.current_page).to eq(1)
171
+ expect(search.results.first.internal_id).to eq('123')
172
+ expect(search.results.first.external_id).to eq('456')
171
173
  expect(search.results.first.alt_name).to eq('A Awesome Name')
174
+ expect(search.results.first.custom_field_list.custitem_stringfield.value).to eq('sample string value')
175
+ expect(search.results.first.custom_field_list.custitem_apcategoryforsales.value.internal_id).to eq('4')
172
176
  expect(search.results.last.email).to eq('alessawesome@gmail.com')
173
177
  end
178
+
179
+ it "should handle an ID search with basic search only field result columns" do
180
+ response = File.read('spec/support/fixtures/search/saved_search_item.xml')
181
+ savon.expects(:search)
182
+ .with(message: {
183
+ "searchRecord"=>{
184
+ "@xsi:type" =>"listAcct:ItemSearchAdvanced",
185
+ "@savedSearchId" =>42,
186
+ :content! =>{"listAcct:criteria"=>{}},
187
+ }
188
+ }).returns(response)
189
+
190
+ search = NetSuite::Records::InventoryItem.search(saved: 42)
191
+
192
+ expect(search.results.first.location_quantity_available).to eq('3307.0')
193
+ expect(search.results.first.location_re_order_point).to eq('2565.0')
194
+ expect(search.results.first.location_quantity_on_order).to eq('40000.0')
195
+ end
174
196
  end
175
197
 
176
198
  context "advanced search" do
@@ -29,10 +29,12 @@ describe NetSuite::Configuration do
29
29
  end
30
30
 
31
31
  describe '#connection' do
32
+ EXAMPLE_ENDPOINT = 'https://1023.suitetalk.api.netsuite.com/services/NetSuitePort_2020_2'
32
33
  before(:each) do
33
34
  # reset clears out the password info
34
35
  config.email 'me@example.com'
35
36
  config.password 'me@example.com'
37
+ config.endpoint EXAMPLE_ENDPOINT
36
38
  config.account 1023
37
39
  config.wsdl "my_wsdl"
38
40
  config.api_version "2012_2"
@@ -57,6 +59,19 @@ describe NetSuite::Configuration do
57
59
 
58
60
  expect(config).to have_received(:cached_wsdl)
59
61
  end
62
+
63
+ it 'sets the endpoint on the Savon client' do
64
+ # this is ugly/brittle, but it's hard to see how else to test this
65
+ savon_configs = config.connection.globals.instance_eval {@options}
66
+ expect(savon_configs.fetch(:endpoint)).to eq(EXAMPLE_ENDPOINT)
67
+ end
68
+
69
+ it 'handles a nil endpoint' do
70
+ config.endpoint = nil
71
+ # this is ugly/brittle, but it's hard to see how else to test this
72
+ savon_configs = config.connection.globals.instance_eval {@options}
73
+ expect(savon_configs.fetch(:endpoint)).to eq(nil)
74
+ end
60
75
  end
61
76
 
62
77
  describe '#wsdl' do
@@ -166,6 +181,23 @@ describe NetSuite::Configuration do
166
181
  end
167
182
  end
168
183
 
184
+ describe '#endpoint' do
185
+ it 'can be set with endpoint=' do
186
+ config.endpoint = 42
187
+ expect(config.endpoint).to eq(42)
188
+ end
189
+
190
+ it 'can be set with just endpoint(value)' do
191
+ config.endpoint(42)
192
+ expect(config.endpoint).to eq(42)
193
+ end
194
+
195
+ it 'supports nil endpoints' do
196
+ config.endpoint = nil
197
+ expect(config.endpoint).to eq(nil)
198
+ end
199
+ end
200
+
169
201
  describe '#auth_header' do
170
202
  context 'when doing user authentication' do
171
203
  before do
@@ -326,15 +358,11 @@ describe NetSuite::Configuration do
326
358
 
327
359
  describe "#credentials" do
328
360
  context "when none are defined" do
329
- skip "should properly create the auth credentials" do
330
-
331
- end
361
+ skip "should properly create the auth credentials"
332
362
  end
333
363
 
334
364
  context "when they are defined" do
335
- it "should properly replace the default auth credentials" do
336
-
337
- end
365
+ skip "should properly replace the default auth credentials"
338
366
  end
339
367
  end
340
368
 
@@ -371,6 +399,65 @@ describe NetSuite::Configuration do
371
399
  end
372
400
  end
373
401
 
402
+ describe "#log" do
403
+ it 'allows a file path to be set as the log destination' do
404
+ file_path = Tempfile.new('tmplog').path
405
+ config.log = file_path
406
+ config.logger.info "foo"
407
+
408
+ log_contents = open(file_path).read
409
+ expect(log_contents).to include("foo")
410
+ end
411
+
412
+ it 'allows an IO device to bet set as the log destination' do
413
+ stream = StringIO.new
414
+ config.log = stream
415
+ config.logger.info "foo"
416
+
417
+ expect(stream.string).to include("foo")
418
+ end
419
+ end
420
+
421
+ describe '#log_level' do
422
+ it 'defaults to :debug' do
423
+ expect(config.log_level).to eq(:debug)
424
+ end
425
+
426
+ it 'can be initially set to any log level' do
427
+ config.log_level(:info)
428
+
429
+ expect(config.log_level).to eq(:info)
430
+ end
431
+
432
+ it 'can override itself' do
433
+ config.log_level = :info
434
+
435
+ expect(config.log_level).to eq(:info)
436
+
437
+ config.log_level(:debug)
438
+
439
+ expect(config.log_level).to eq(:debug)
440
+ end
441
+ end
442
+
443
+ describe '#log_level=' do
444
+ it 'can set the initial log_level' do
445
+ config.log_level = :info
446
+
447
+ expect(config.log_level).to eq(:info)
448
+ end
449
+
450
+ it 'can override a previously set log level' do
451
+ config.log_level = :info
452
+
453
+ expect(config.log_level).to eq(:info)
454
+
455
+ config.log_level = :debug
456
+
457
+ expect(config.log_level).to eq(:debug)
458
+ end
459
+ end
460
+
374
461
  describe 'timeouts' do
375
462
  it 'has defaults' do
376
463
  expect(config.read_timeout).to eql(60)
@@ -1,6 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'basic records' do
4
+ # all records with internal IDs should be added to this list
4
5
  let(:basic_record_list) {
5
6
  [
6
7
  NetSuite::Records::Currency,
@@ -49,6 +50,7 @@ describe 'basic records' do
49
50
  NetSuite::Records::SerializedInventoryItem,
50
51
  NetSuite::Records::DepositApplication,
51
52
  NetSuite::Records::InventoryAdjustment,
53
+ NetSuite::Records::Vendor,
52
54
  NetSuite::Records::VendorReturnAuthorization,
53
55
  NetSuite::Records::AssemblyBuild,
54
56
  NetSuite::Records::AssemblyUnbuild,
@@ -61,6 +63,7 @@ describe 'basic records' do
61
63
  NetSuite::Records::BinTransfer,
62
64
  NetSuite::Records::SerializedAssemblyItem,
63
65
  NetSuite::Records::CustomerStatus,
66
+ NetSuite::Records::CustomerPayment,
64
67
  NetSuite::Records::TransactionBodyCustomField,
65
68
  NetSuite::Records::TransactionColumnCustomField,
66
69
  NetSuite::Records::EntityCustomField
@@ -108,8 +111,12 @@ describe 'basic records' do
108
111
 
109
112
  if !sublist_fields.empty?
110
113
  sublist_fields.each do |sublist_field|
114
+ sublist = record_instance.send(sublist_field)
115
+
111
116
  # TODO make a sublist entry with some fields valid for that sublist item
112
- record_instance.send(sublist_field) << {}
117
+ sublist << {}
118
+
119
+ expect(sublist.send(sublist.sublist_key).count).to be(1)
113
120
  end
114
121
  end
115
122
 
@@ -5,12 +5,21 @@ describe NetSuite::Records::Classification do
5
5
 
6
6
  it 'has all the right fields' do
7
7
  [
8
- :name, :include_children, :is_inactive, :class_translation_list, :custom_field_list
8
+ :name, :include_children, :is_inactive, :class_translation_list
9
9
  ].each do |field|
10
10
  expect(classification).to have_field(field)
11
11
  end
12
12
 
13
13
  expect(classification.subsidiary_list.class).to eq(NetSuite::Records::RecordRefList)
14
+ expect(classification.custom_field_list.class).to eq(NetSuite::Records::CustomFieldList)
15
+ end
16
+
17
+ it 'has all the right record refs' do
18
+ [
19
+ :parent
20
+ ].each do |record_ref|
21
+ expect(classification).to have_record_ref(record_ref)
22
+ end
14
23
  end
15
24
 
16
25
  describe '.get' do
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe NetSuite::Records::CostCategory do
4
+ let(:cost_category) { described_class.new }
5
+
6
+ it 'has all the right fields' do
7
+ [
8
+ :is_inactive,
9
+ :item_cost_type,
10
+ :name,
11
+ ].each do |field|
12
+ expect(cost_category).to have_field(field)
13
+ end
14
+ end
15
+
16
+ it 'has all the right record refs' do
17
+ [
18
+ :account,
19
+ ].each do |record_ref|
20
+ expect(cost_category).to have_record_ref(record_ref)
21
+ end
22
+ end
23
+
24
+ describe '.get' do
25
+ context 'when the response is successful' do
26
+ let(:response) { NetSuite::Response.new(:success => true, :body => { :name => 'CostCategory 1' }) }
27
+
28
+ it 'returns a CostCategory instance populated with the data from the response object' do
29
+ expect(NetSuite::Actions::Get).to receive(:call).with([described_class, {:external_id => 1}], {}).and_return(response)
30
+ cost_category = described_class.get(:external_id => 1)
31
+ expect(cost_category).to be_kind_of(described_class)
32
+ expect(cost_category.name).to eql('CostCategory 1')
33
+ end
34
+ end
35
+
36
+ context 'when the response is unsuccessful' do
37
+ let(:response) { NetSuite::Response.new(:success => false, :body => {}) }
38
+
39
+ it 'raises a RecordNotFound exception' do
40
+ expect(NetSuite::Actions::Get).to receive(:call).with([described_class, {:external_id => 1}], {}).and_return(response)
41
+ expect {
42
+ described_class.get(:external_id => 1)
43
+ }.to raise_error(NetSuite::RecordNotFound,
44
+ /NetSuite::Records::CostCategory with OPTIONS=(.*) could not be found/)
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '#add' do
50
+ let(:test_data) { { :name => 'Test CostCategory' } }
51
+
52
+ context 'when the response is successful' do
53
+ let(:response) { NetSuite::Response.new(:success => true, :body => { :internal_id => '1' }) }
54
+
55
+ it 'returns true' do
56
+ cost_category = described_class.new(test_data)
57
+ expect(NetSuite::Actions::Add).to receive(:call).
58
+ with([cost_category], {}).
59
+ and_return(response)
60
+ expect(cost_category.add).to be_truthy
61
+ end
62
+ end
63
+
64
+ context 'when the response is unsuccessful' do
65
+ let(:response) { NetSuite::Response.new(:success => false, :body => {}) }
66
+
67
+ it 'returns false' do
68
+ cost_category = described_class.new(test_data)
69
+ expect(NetSuite::Actions::Add).to receive(:call).
70
+ with([cost_category], {}).
71
+ and_return(response)
72
+ expect(cost_category.add).to be_falsey
73
+ end
74
+ end
75
+ end
76
+
77
+ describe '#delete' do
78
+ let(:test_data) { { :internal_id => '1' } }
79
+
80
+ context 'when the response is successful' do
81
+ let(:response) { NetSuite::Response.new(:success => true, :body => { :internal_id => '1' }) }
82
+
83
+ it 'returns true' do
84
+ cost_category = described_class.new(test_data)
85
+ expect(NetSuite::Actions::Delete).to receive(:call).
86
+ with([cost_category], {}).
87
+ and_return(response)
88
+ expect(cost_category.delete).to be_truthy
89
+ end
90
+ end
91
+
92
+ context 'when the response is unsuccessful' do
93
+ let(:response) { NetSuite::Response.new(:success => false, :body => {}) }
94
+
95
+ it 'returns false' do
96
+ cost_category = described_class.new(test_data)
97
+ expect(NetSuite::Actions::Delete).to receive(:call).
98
+ with([cost_category], {}).
99
+ and_return(response)
100
+ expect(cost_category.delete).to be_falsey
101
+ end
102
+ end
103
+ end
104
+
105
+ end
@@ -3,17 +3,53 @@ require 'spec_helper'
3
3
  describe NetSuite::Records::CustomFieldList do
4
4
  let(:list) { NetSuite::Records::CustomFieldList.new }
5
5
 
6
+ before(:all) { savon.mock! }
7
+ after(:all) { savon.unmock! }
8
+
6
9
  it 'has a custom_fields attribute' do
7
10
  expect(list.custom_fields).to be_kind_of(Array)
8
11
  end
9
12
 
10
13
  it 'accepts a collection of CustomField records' do
11
- field = NetSuite::Records::CustomField.new({:value=>{:internal_id=>"5", :type_id=>"103"},
12
- :script_id=>"custitem_item_category", :"@xsi:type"=>"platformCore:SelectCustomFieldRef"})
14
+ field = NetSuite::Records::CustomField.new({
15
+ :value=>{:internal_id=>"5", :type_id=>"103"},
16
+ :script_id=>"custitem_item_category",
17
+ :"@xsi:type"=>"platformCore:SelectCustomFieldRef"
18
+ })
19
+
13
20
  list = described_class.new(custom_field: [field])
21
+
14
22
  expect(list.custom_fields).to eq([field])
15
23
  end
16
24
 
25
+ it 'properly decodes various custom field types' do
26
+ savon.
27
+ expects(:get).
28
+ with(message: {"platformMsgs:baseRef"=>{"@xsi:type"=>"platformCore:RecordRef", "@internalId"=>123, "@type"=>"creditMemo"}}).
29
+ returns(File.read('spec/support/fixtures/custom_fields/multi_select.xml'))
30
+
31
+ credit_memo_with_custom_fields = NetSuite::Records::CreditMemo.get(123)
32
+
33
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_standard_select.value.internal_id).to eq("2")
34
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_standard_select.value.attributes[:name]).to eq("Manual")
35
+
36
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_date_field.value).to be_a(DateTime)
37
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_date_field.value.to_s).to eq("2021-07-13T22:00:00-07:00")
38
+
39
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_string_field.value).to eq("a very nice string")
40
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_boolean_field.value).to eq(false)
41
+
42
+ # even if there's a single value, it should return an array
43
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_field.value).to be_a(Array)
44
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_field.value.size).to eq(1)
45
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_field.value.first.attributes[:name]).to eq("selection value")
46
+
47
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_with_multiple.value).to be_a(Array)
48
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_with_multiple.value.size).to eq(2)
49
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_with_multiple.value.first.attributes[:name]).to eq("selection value 1")
50
+ expect(credit_memo_with_custom_fields.custom_field_list.custbody_multi_select_with_multiple.value.last.attributes[:name]).to eq("selection value 2")
51
+ end
52
+
17
53
  context 'initializing with custom field attributes without a type' do
18
54
  it 'does not mutate the attributes' do
19
55
  field = {:value=>{:internal_id=>"5", :type_id=>"103"},
@@ -28,7 +64,9 @@ describe NetSuite::Records::CustomFieldList do
28
64
  it 'does not mutate the attributes' do
29
65
  field = {:value=>{:internal_id=>"5", :type_id=>"103"},
30
66
  :script_id=>"custitem_item_category", :"@xsi:type"=>"platformCore:SelectCustomFieldRef"}
67
+
31
68
  described_class.new(custom_field: [field])
69
+
32
70
  expect(field).to eq({:value=>{:internal_id=>"5", :type_id=>"103"},
33
71
  :script_id=>"custitem_item_category", :"@xsi:type"=>"platformCore:SelectCustomFieldRef"})
34
72
  end
@@ -37,9 +75,11 @@ describe NetSuite::Records::CustomFieldList do
37
75
  context 'writing convience methods' do
38
76
  it "should create a custom field entry when none exists" do
39
77
  list.custrecord_somefield = 'a value'
40
- list.custom_fields.size.should == 1
41
- list.custom_fields.first.value.should == 'a value'
42
- list.custom_fields.first.type.should == 'platformCore:StringCustomFieldRef'
78
+ custom_fields = list.custom_fields
79
+
80
+ expect(custom_fields.size).to eq(1)
81
+ expect(custom_fields.first.value).to eq('a value')
82
+ expect(custom_fields.first.type).to eq('platformCore:StringCustomFieldRef')
43
83
  end
44
84
 
45
85
  # https://github.com/NetSweet/netsuite/issues/325
@@ -116,7 +156,7 @@ describe NetSuite::Records::CustomFieldList do
116
156
  end
117
157
 
118
158
  it "should raise an error if custom field entry does not exist" do
119
- expect{ list.nonexisting_custom_field }.to raise_error
159
+ expect{ list.nonexisting_custom_field }.to raise_error(NoMethodError)
120
160
  end
121
161
  end
122
162
  end
@@ -18,7 +18,7 @@ describe NetSuite::Records::CustomRecord do
18
18
 
19
19
  it 'has all the right record_refs' do
20
20
  [
21
- :custom_form, :owner
21
+ :custom_form, :owner, :rec_type, :parent
22
22
  ].each do |record_ref|
23
23
  expect(record).to have_record_ref(record_ref)
24
24
  end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe NetSuite::Records::CustomerCreditCardsList do
4
+ let(:list) { NetSuite::Records::CustomerCreditCardsList.new }
5
+
6
+ it 'has a credit_cards attribute' do
7
+ expect(list.credit_cards).to be_kind_of(Array)
8
+ end
9
+
10
+ describe '#to_record' do
11
+ it 'can represent itself as a SOAP record' do
12
+ list.replace_all = true
13
+
14
+ record = {
15
+ 'listRel:creditCards' => [],
16
+ 'listRel:replaceAll' => true
17
+ }
18
+
19
+ expect(list.to_record).to eql(record)
20
+ end
21
+ end
22
+
23
+ end