magento 0.24.0 → 0.28.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/.gitignore +4 -2
- data/Gemfile +5 -3
- data/README.md +636 -226
- data/lib/magento.rb +7 -1
- data/lib/magento/cart.rb +65 -0
- data/lib/magento/order.rb +47 -2
- data/lib/magento/params/create_image.rb +43 -0
- data/lib/magento/params/create_product_link.rb +30 -0
- data/lib/magento/product.rb +96 -1
- data/lib/magento/query.rb +13 -10
- data/lib/magento/sales_rule.rb +4 -0
- data/lib/magento/version.rb +1 -1
- data/spec/magento/core/model_mapper_spec.rb +74 -0
- data/spec/magento/core/model_spec.rb +71 -0
- data/spec/magento/core/query_spec.rb +207 -0
- data/spec/magento/core/record_collection_spec.rb +116 -0
- data/spec/magento/core/request_spec.rb +141 -0
- data/spec/magento/order_spec.rb +37 -0
- data/spec/{product_spec.rb → magento/product_spec.rb} +21 -0
- data/spec/spec_helper.rb +17 -3
- data/spec/vcr_cassettes/order/send_email.yml +65 -0
- data/spec/vcr_cassettes/product/find.yml +72 -0
- metadata +13 -4
- data/.rspec_status +0 -5
@@ -0,0 +1,71 @@
|
|
1
|
+
RSpec.describe Magento::Model do
|
2
|
+
describe 'public method' do
|
3
|
+
describe '.find' do
|
4
|
+
it 'is pending'
|
5
|
+
end
|
6
|
+
|
7
|
+
describe '.create' do
|
8
|
+
it 'is pending'
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '.update' do
|
12
|
+
it 'is pending'
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '.delete' do
|
16
|
+
it 'is pending'
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#save' do
|
20
|
+
it 'calls the update class method'
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#update' do
|
24
|
+
it 'calls the update class method'
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#delete' do
|
28
|
+
it 'calls the delete class method'
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '.api_resource' do
|
32
|
+
it 'is pending'
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '.entity_name' do
|
36
|
+
it 'is pending'
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '.primary_key' do
|
40
|
+
it 'is pending'
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'delegated methods from query' do
|
44
|
+
it 'respond to .all'
|
45
|
+
it 'respond to .find_each'
|
46
|
+
it 'respond to .page'
|
47
|
+
it 'respond to .per'
|
48
|
+
it 'respond to .page_size'
|
49
|
+
it 'respond to .order'
|
50
|
+
it 'respond to .select'
|
51
|
+
it 'respond to .where'
|
52
|
+
it 'respond to .first'
|
53
|
+
it 'respond to .find_by'
|
54
|
+
it 'respond to .count'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'protected method' do
|
59
|
+
describe '.entity_key' do
|
60
|
+
it 'is pending'
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '.query' do
|
64
|
+
it 'is pending'
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '.request' do
|
68
|
+
it 'is pending'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
class Magento::Faker < Magento::Model; end
|
2
|
+
|
3
|
+
RSpec.describe Magento::Query do
|
4
|
+
subject { Magento::Query.new(Magento::Faker) }
|
5
|
+
|
6
|
+
describe '#where' do
|
7
|
+
it 'add the filter to group of filters' do
|
8
|
+
subject.where(price_gt: 50)
|
9
|
+
|
10
|
+
expect(subject.send(:filter_groups)).to eql([
|
11
|
+
{ filters: [{ field: 'price', conditionType: 'gt', value: 50 }] }
|
12
|
+
])
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when the condition is not passed' do
|
16
|
+
it 'the "eq" condition is used as default' do
|
17
|
+
subject.where(price: 50)
|
18
|
+
|
19
|
+
expect(subject.send(:filter_groups)).to eql([
|
20
|
+
{ filters: [{ field: :price, conditionType: 'eq', value: 50 }] }
|
21
|
+
])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when it is called more than once' do
|
26
|
+
it 'adds filter in diferent groups' do
|
27
|
+
subject.where(price_gt: 10).where(price_lt: 20)
|
28
|
+
|
29
|
+
expect(subject.send(:filter_groups)).to eql([
|
30
|
+
{ filters: [{ field: 'price', conditionType: 'gt', value: 10 }] },
|
31
|
+
{ filters: [{ field: 'price', conditionType: 'lt', value: 20 }] }
|
32
|
+
])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when it is called with more than one filter' do
|
37
|
+
it 'adds the filters in same group' do
|
38
|
+
subject.where(price_gt: 10, price_lt: 20)
|
39
|
+
|
40
|
+
expect(subject.send(:filter_groups)).to eql([
|
41
|
+
{
|
42
|
+
filters: [
|
43
|
+
{ field: 'price', conditionType: 'gt', value: 10 },
|
44
|
+
{ field: 'price', conditionType: 'lt', value: 20 }
|
45
|
+
]
|
46
|
+
}
|
47
|
+
])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when the condition is "in" or "nin" and value is a Array' do
|
52
|
+
it 'converts the value to string' do
|
53
|
+
subject.where(status_in: [:pending, :new])
|
54
|
+
subject.where(entity_id_nin: [123, 321])
|
55
|
+
|
56
|
+
expect(subject.send(:filter_groups)).to eql([
|
57
|
+
{ filters: [{ field: 'status', conditionType: 'in', value: 'pending,new' }] },
|
58
|
+
{ filters: [{ field: 'entity_id', conditionType: 'nin', value: '123,321' }] }
|
59
|
+
])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#page' do
|
65
|
+
it do
|
66
|
+
subject.page(2)
|
67
|
+
expect(subject.send(:current_page)).to eql(2)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#page_size' do
|
72
|
+
it do
|
73
|
+
subject.page_size(5)
|
74
|
+
expect(subject.instance_variable_get(:@page_size)).to eql(5)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#select' do
|
79
|
+
it 'set fields inside items[]' do
|
80
|
+
subject.select(:id, :name)
|
81
|
+
|
82
|
+
expect(subject.send(:fields)).to eql('items[id,name],search_criteria,total_count')
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'allow hash' do
|
86
|
+
subject.select(:id, nested_attribute: :name)
|
87
|
+
|
88
|
+
expect(subject.send(:fields)).to eql('items[id,nested_attribute[name]],search_criteria,total_count')
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'allow hash with key and value as array' do
|
92
|
+
subject.select(:id, nested_attribute: [:id, :name])
|
93
|
+
|
94
|
+
expect(subject.send(:fields)).to eql('items[id,nested_attribute[id,name]],search_criteria,total_count')
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'allow hash multiple level' do
|
98
|
+
subject.select(:id, nested_attribute: [:id, :name, stock: :quantity])
|
99
|
+
|
100
|
+
expect(subject.send(:fields)).to eql(
|
101
|
+
'items[id,nested_attribute[id,name,stock[quantity]]],search_criteria,total_count'
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when model is Magento::Category' do
|
106
|
+
class Magento::Category < Magento::Model; end
|
107
|
+
|
108
|
+
subject { Magento::Query.new(Magento::Category) }
|
109
|
+
|
110
|
+
it 'set fields inseide children_data[]' do
|
111
|
+
subject.select(:id, :name)
|
112
|
+
|
113
|
+
expect(subject.send(:fields)).to eql('children_data[id,name]')
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#order' do
|
119
|
+
it 'set order in sort_orders' do
|
120
|
+
subject.order(name: :desc)
|
121
|
+
|
122
|
+
expect(subject.send(:sort_orders)).to eql(
|
123
|
+
[{ field: :name, direction: :desc }]
|
124
|
+
)
|
125
|
+
|
126
|
+
subject.order(created_at: :desc, name: :asc)
|
127
|
+
|
128
|
+
expect(subject.send(:sort_orders)).to eql(
|
129
|
+
[
|
130
|
+
{ field: :created_at, direction: :desc },
|
131
|
+
{ field: :name, direction: :asc }
|
132
|
+
]
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'when the direction is not passed' do
|
137
|
+
it 'the :asc direction is used as default' do
|
138
|
+
subject.order(:name)
|
139
|
+
|
140
|
+
expect(subject.send(:sort_orders)).to eql(
|
141
|
+
[{ field: :name, direction: :asc }]
|
142
|
+
)
|
143
|
+
|
144
|
+
subject.order(:created_at, :name)
|
145
|
+
|
146
|
+
expect(subject.send(:sort_orders)).to eql([
|
147
|
+
{ field: :created_at, direction: :asc },
|
148
|
+
{ field: :name, direction: :asc }
|
149
|
+
])
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe '#all' do
|
155
|
+
it 'is pending'
|
156
|
+
end
|
157
|
+
|
158
|
+
describe '#first' do
|
159
|
+
it 'is pending'
|
160
|
+
end
|
161
|
+
|
162
|
+
describe '#find_by' do
|
163
|
+
it 'is pending'
|
164
|
+
end
|
165
|
+
|
166
|
+
describe '#count' do
|
167
|
+
it 'is pending'
|
168
|
+
end
|
169
|
+
|
170
|
+
describe '#find_each' do
|
171
|
+
it 'is pending'
|
172
|
+
end
|
173
|
+
|
174
|
+
describe 'private mathods' do
|
175
|
+
describe 'endpoint' do
|
176
|
+
it 'is pending'
|
177
|
+
end
|
178
|
+
|
179
|
+
describe 'verify_id' do
|
180
|
+
it 'is pending'
|
181
|
+
end
|
182
|
+
|
183
|
+
describe 'query_params' do
|
184
|
+
it 'is pending'
|
185
|
+
end
|
186
|
+
|
187
|
+
describe 'parse_filter' do
|
188
|
+
it 'is pending'
|
189
|
+
end
|
190
|
+
|
191
|
+
describe 'parse_value_filter' do
|
192
|
+
it 'is pending'
|
193
|
+
end
|
194
|
+
|
195
|
+
describe 'parse_field' do
|
196
|
+
it 'is pending'
|
197
|
+
end
|
198
|
+
|
199
|
+
describe 'encode' do
|
200
|
+
it 'is pending'
|
201
|
+
end
|
202
|
+
|
203
|
+
describe 'append_key' do
|
204
|
+
it 'is pending'
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
RSpec.describe Magento::RecordCollection do
|
2
|
+
subject { Magento::RecordCollection.new(items: []) }
|
3
|
+
|
4
|
+
describe 'read only attributes' do
|
5
|
+
it { is_expected.to respond_to(:items) }
|
6
|
+
it { is_expected.to respond_to(:search_criteria) }
|
7
|
+
it { is_expected.to respond_to(:total_count) }
|
8
|
+
it { is_expected.not_to respond_to(:items=) }
|
9
|
+
it { is_expected.not_to respond_to(:search_criteria=) }
|
10
|
+
it { is_expected.not_to respond_to(:total_count=) }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#last_page?' do
|
14
|
+
it do
|
15
|
+
subject = create_subject_with_pagination(total_count: 60, current_page: 6, page_size: 10)
|
16
|
+
expect(subject.last_page?).to be true
|
17
|
+
end
|
18
|
+
|
19
|
+
it do
|
20
|
+
subject = create_subject_with_pagination(total_count: 60, current_page: 5, page_size: 10)
|
21
|
+
expect(subject.last_page?).to be false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#next_page' do
|
26
|
+
it 'returns next page number' do
|
27
|
+
subject = create_subject_with_pagination(current_page: 5, total_count: 60, page_size: 10)
|
28
|
+
expect(subject.next_page).to be 6
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns nil when current page is the last' do
|
32
|
+
subject = create_subject_with_pagination(current_page: 6, total_count: 60, page_size: 10)
|
33
|
+
expect(subject.next_page).to be nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '.from_magento_response' do
|
38
|
+
let(:response) do
|
39
|
+
{
|
40
|
+
'items' => [
|
41
|
+
{ 'id' => 1, 'name' => 'Product one' },
|
42
|
+
{ 'id' => 2, 'name' => 'Product two' }
|
43
|
+
],
|
44
|
+
'total_count' => 12,
|
45
|
+
'search_criteria' => { 'current_page' => 2, 'page_size' => 10 }
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'create RecordCollection instance from magento response' do
|
50
|
+
records = Magento::RecordCollection.from_magento_response(response, model: Magento::Product)
|
51
|
+
|
52
|
+
expect(records).to all be_a_instance_of(Magento::Product)
|
53
|
+
expect(records.size).to eql(2)
|
54
|
+
expect(records.total_count).to eql(12)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'allows specify the iterable field' do
|
58
|
+
response['data'] = response.delete 'items'
|
59
|
+
|
60
|
+
records = Magento::RecordCollection.from_magento_response(
|
61
|
+
response,
|
62
|
+
model: Magento::Product,
|
63
|
+
iterable_field: 'data'
|
64
|
+
)
|
65
|
+
|
66
|
+
expect(records.size).to eql(2)
|
67
|
+
expect(records).to all be_a_instance_of(Magento::Product)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'delegated methods' do
|
72
|
+
let(:methods) do
|
73
|
+
%i[
|
74
|
+
count
|
75
|
+
length
|
76
|
+
size
|
77
|
+
first
|
78
|
+
last
|
79
|
+
[]
|
80
|
+
find
|
81
|
+
each
|
82
|
+
each_with_index
|
83
|
+
sample
|
84
|
+
map
|
85
|
+
select
|
86
|
+
filter
|
87
|
+
reject
|
88
|
+
collect
|
89
|
+
take
|
90
|
+
take_while
|
91
|
+
sort
|
92
|
+
sort_by
|
93
|
+
reverse_each
|
94
|
+
reverse
|
95
|
+
all?
|
96
|
+
any?
|
97
|
+
none?
|
98
|
+
one?
|
99
|
+
empty?
|
100
|
+
]
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'from #items' do
|
104
|
+
methods.each do |method|
|
105
|
+
expect(subject).to respond_to(method)
|
106
|
+
expect(subject.items).to receive(method)
|
107
|
+
subject.send(method)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def create_subject_with_pagination(total_count:, current_page:, page_size:)
|
113
|
+
search_criteria = double(:search_criteria, current_page: current_page, page_size: page_size)
|
114
|
+
Magento::RecordCollection.new(items: [], total_count: total_count, search_criteria: search_criteria)
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
RSpec.describe Magento::Request do
|
2
|
+
let(:config) do
|
3
|
+
double('Magento::Configuration',
|
4
|
+
url: 'https://site.com.br',
|
5
|
+
token: 'magento-token',
|
6
|
+
store: 'magento-store',
|
7
|
+
timeout: 30,
|
8
|
+
open_timeout: 5
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
subject { Magento::Request.new(config: config) }
|
13
|
+
|
14
|
+
let(:response) do
|
15
|
+
double('Response', parse: {}, status: double(:status, success?: true))
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#get' do
|
19
|
+
it 'calls HTTP.get with url' do
|
20
|
+
expect_any_instance_of(HTTP::Client).to receive(:get)
|
21
|
+
.with('https://site.com.br/rest/magento-store/V1/products')
|
22
|
+
.and_return(response)
|
23
|
+
|
24
|
+
subject.get('products')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#put' do
|
29
|
+
it 'calls HTTP.put with url and body' do
|
30
|
+
body = { product: { price: 22.50 } }
|
31
|
+
|
32
|
+
expect_any_instance_of(HTTP::Client).to receive(:put)
|
33
|
+
.with('https://site.com.br/rest/magento-store/V1/products', { json: body })
|
34
|
+
.and_return(response)
|
35
|
+
|
36
|
+
subject.put('products', body)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#post' do
|
41
|
+
it 'calls HTTP.post with url and body' do
|
42
|
+
body = { product: { name: 'Some name', price: 22.50 } }
|
43
|
+
|
44
|
+
expect_any_instance_of(HTTP::Client).to receive(:post)
|
45
|
+
.with('https://site.com.br/rest/magento-store/V1/products', { json: body })
|
46
|
+
.and_return(response)
|
47
|
+
|
48
|
+
subject.post('products', body)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#delete' do
|
53
|
+
it 'calls HTTP.selete with url' do
|
54
|
+
expect_any_instance_of(HTTP::Client).to receive(:delete)
|
55
|
+
.with('https://site.com.br/rest/magento-store/V1/products/22')
|
56
|
+
.and_return(response)
|
57
|
+
|
58
|
+
subject.delete('products/22')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'private method' do
|
63
|
+
describe '#http_auth' do
|
64
|
+
it 'calls HTTP.auth with token and returns HTTP::Client' do
|
65
|
+
expect(HTTP).to receive(:auth).with("Bearer #{config.token}").and_return(HTTP)
|
66
|
+
result = subject.send(:http_auth)
|
67
|
+
expect(result).to be_a(HTTP::Client)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#base_url' do
|
72
|
+
it do
|
73
|
+
base_url = "https://site.com.br/rest/magento-store/V1"
|
74
|
+
expect(subject.send(:base_url)).to eql(base_url)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#url' do
|
79
|
+
it 'returns base_url + resource' do
|
80
|
+
url = "https://site.com.br/rest/magento-store/V1/products"
|
81
|
+
expect(subject.send(:url, 'products')).to eql(url)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#handle_error' do
|
86
|
+
context 'when success' do
|
87
|
+
it 'does nothing' do
|
88
|
+
subject.send(:handle_error, response)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when status not found' do
|
93
|
+
it 'reises Magento::NotFound error' do
|
94
|
+
allow(response).to receive(:status).and_return(
|
95
|
+
double(:status, success?: false, not_found?: true, code: 404)
|
96
|
+
)
|
97
|
+
|
98
|
+
expect { subject.send(:handle_error, response) }.to raise_error(Magento::NotFound)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when other status' do
|
103
|
+
it 'reises Magento::MagentoError' do
|
104
|
+
allow(response).to receive(:status).and_return(
|
105
|
+
double(:status, success?: false, not_found?: false, code: 422)
|
106
|
+
)
|
107
|
+
|
108
|
+
expect { subject.send(:handle_error, response) }.to raise_error(Magento::MagentoError)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#save_request' do
|
114
|
+
it 'save on instance variable' do
|
115
|
+
body = { quantity: 200, category_ids: [1,3,4] }
|
116
|
+
|
117
|
+
subject.send(:save_request, :post, 'https:someurl.com.br', body)
|
118
|
+
|
119
|
+
expect(subject.instance_variable_get(:@request)).to eql({
|
120
|
+
body: body,
|
121
|
+
method: :post,
|
122
|
+
url: 'https:someurl.com.br',
|
123
|
+
})
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'when body has media_gallery_entries' do
|
127
|
+
it 'removes media_gallery_entries attribute from body' do
|
128
|
+
body = { product: { name: 'Name', price: 99.90, media_gallery_entries: {} } }
|
129
|
+
|
130
|
+
subject.send(:save_request, :post, 'https:someurl.com.br', body)
|
131
|
+
|
132
|
+
expect(subject.instance_variable_get(:@request)).to eql({
|
133
|
+
body: { name: 'Name', price: 99.90 },
|
134
|
+
method: :post,
|
135
|
+
url: 'https:someurl.com.br',
|
136
|
+
})
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|