magento 0.25.0 → 0.28.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- 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/product.rb +88 -0
- data/lib/magento/query.rb +11 -9
- data/lib/magento/request.rb +6 -1
- 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 +12 -3
@@ -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
|