auchandirect-scrAPI 0.0.1
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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +26 -0
- data/.rspec +1 -0
- data/.travis.yml +17 -0
- data/Gemfile +4 -0
- data/Guardfile +9 -0
- data/LICENSE +165 -0
- data/README.md +29 -0
- data/Rakefile +7 -0
- data/auchandirect-scrAPI.gemspec +27 -0
- data/lib/auchandirect/scrAPI.rb +29 -0
- data/lib/auchandirect/scrAPI/base_cart.rb +68 -0
- data/lib/auchandirect/scrAPI/cart.rb +173 -0
- data/lib/auchandirect/scrAPI/dummy_cart.rb +128 -0
- data/lib/auchandirect/scrAPI/invalid_account_error.rb +27 -0
- data/lib/auchandirect/scrAPI/items.rb +62 -0
- data/lib/auchandirect/scrAPI/version.rb +27 -0
- data/lib/auchandirect/scrAPI/webrick_uri_escape_monkey_patch.rb +37 -0
- data/spec/lib/auchandirect/scrAPI/cart_shared_examples.rb +189 -0
- data/spec/lib/auchandirect/scrAPI/cart_spec.rb +51 -0
- data/spec/lib/auchandirect/scrAPI/client_cart_shared_examples.rb +60 -0
- data/spec/lib/auchandirect/scrAPI/dummy_cart_spec.rb +40 -0
- data/spec/lib/auchandirect/scrAPI/items_spec.rb +44 -0
- data/spec/lib/auchandirect/scrAPI/offline_items_spec.rb +114 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/support/enumerator_lazy.rb +38 -0
- data/spec/support/offline_test_helper.rb +49 -0
- data/spec/support_spec/enumerator_lazy_spec.rb +42 -0
- metadata +178 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,128 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# auchandirect/scrAPI/dummy_cart.rb
|
4
|
+
#
|
5
|
+
# Copyright (c) 2011-2014 by Philippe Bourgau. All rights reserved.
|
6
|
+
#
|
7
|
+
# This library is free software; you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU Lesser General Public
|
9
|
+
# License as published by the Free Software Foundation; either
|
10
|
+
# version 3.0 of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This library is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15
|
+
# Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public
|
18
|
+
# License along with this library; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
20
|
+
# MA 02110-1301 USA
|
21
|
+
|
22
|
+
module Auchandirect
|
23
|
+
module ScrAPI
|
24
|
+
|
25
|
+
# Logger mock api
|
26
|
+
class DummyCart < BaseCart
|
27
|
+
|
28
|
+
def self.url
|
29
|
+
"http://www.#{Storexplore::Testing::DummyStoreConstants::NAME}.com"
|
30
|
+
end
|
31
|
+
def self.valid_email
|
32
|
+
"valid@mail.com"
|
33
|
+
end
|
34
|
+
def self.valid_password
|
35
|
+
"valid-password"
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.logout_url
|
39
|
+
url+"/logout"
|
40
|
+
end
|
41
|
+
def self.login_url
|
42
|
+
url+"/login"
|
43
|
+
end
|
44
|
+
def self.login_parameters(login,password)
|
45
|
+
[{'name' => 'session_data', 'value' => 'crypted_data', 'type' => 'hidden'},
|
46
|
+
{'name' => login_parameter, 'value' => login, 'type' => 'text'},
|
47
|
+
{'name' => password_parameter, 'value' => password, 'type' => 'password'}]
|
48
|
+
end
|
49
|
+
def self.login_parameter
|
50
|
+
'login'
|
51
|
+
end
|
52
|
+
def self.password_parameter
|
53
|
+
'password'
|
54
|
+
end
|
55
|
+
|
56
|
+
attr_reader :login, :password, :log
|
57
|
+
|
58
|
+
def initialize(login = nil, password = nil)
|
59
|
+
@log = []
|
60
|
+
@login = ""
|
61
|
+
@password = ""
|
62
|
+
@unavailable_items = {}
|
63
|
+
@content = Hash.new(0)
|
64
|
+
|
65
|
+
if !login.nil? || !password.nil?
|
66
|
+
relog(login, password)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def relog(login, password)
|
71
|
+
if login != DummyCart.valid_email
|
72
|
+
raise InvalidAccountError.new
|
73
|
+
end
|
74
|
+
|
75
|
+
@log.push(:login)
|
76
|
+
@login = login
|
77
|
+
@password = password
|
78
|
+
end
|
79
|
+
|
80
|
+
def logout
|
81
|
+
@log.push(:logout)
|
82
|
+
end
|
83
|
+
|
84
|
+
def empty_the_cart
|
85
|
+
@log.push(:empty_the_cart)
|
86
|
+
@content.clear
|
87
|
+
end
|
88
|
+
|
89
|
+
def add_to_cart(quantity, item)
|
90
|
+
if available?(item)
|
91
|
+
@log.push(:add_to_cart)
|
92
|
+
@content[item] += quantity
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def cart_value
|
97
|
+
@content.to_a.inject(0.0) do |amount,id_and_quantity|
|
98
|
+
item = id_and_quantity.first
|
99
|
+
quantity = id_and_quantity.last
|
100
|
+
|
101
|
+
unit_price = item.hash.abs.to_f/1e7
|
102
|
+
|
103
|
+
amount + quantity * unit_price
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def content
|
108
|
+
@content.keys
|
109
|
+
end
|
110
|
+
|
111
|
+
def empty?
|
112
|
+
@content.empty?
|
113
|
+
end
|
114
|
+
|
115
|
+
def containing?(item, quantity)
|
116
|
+
@content[item] == quantity
|
117
|
+
end
|
118
|
+
|
119
|
+
def add_unavailable_item(item)
|
120
|
+
@unavailable_items[item] = true
|
121
|
+
end
|
122
|
+
def available?(item)
|
123
|
+
!@unavailable_items[item]
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# auchandirect/scrAPI/invalid_account_error.rb
|
4
|
+
#
|
5
|
+
# Copyright (c) 2011-2014 by Philippe Bourgau. All rights reserved.
|
6
|
+
#
|
7
|
+
# This library is free software; you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU Lesser General Public
|
9
|
+
# License as published by the Free Software Foundation; either
|
10
|
+
# version 3.0 of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This library is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15
|
+
# Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public
|
18
|
+
# License along with this library; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
20
|
+
# MA 02110-1301 USA
|
21
|
+
|
22
|
+
module Auchandirect
|
23
|
+
module ScrAPI
|
24
|
+
class InvalidAccountError < RuntimeError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# auchandirect/scrAPI/items.rb
|
4
|
+
#
|
5
|
+
# Copyright (c) 2010-2014 by Philippe Bourgau. All rights reserved.
|
6
|
+
#
|
7
|
+
# This library is free software; you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU Lesser General Public
|
9
|
+
# License as published by the Free Software Foundation; either
|
10
|
+
# version 3.0 of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This library is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15
|
+
# Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public
|
18
|
+
# License along with this library; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
20
|
+
# MA 02110-1301 USA
|
21
|
+
|
22
|
+
module Auchandirect
|
23
|
+
module ScrAPI
|
24
|
+
|
25
|
+
module Items
|
26
|
+
NAMES_SEPARATOR = ', '
|
27
|
+
end
|
28
|
+
|
29
|
+
Storexplore::Api.define "auchandirect.fr" do
|
30
|
+
|
31
|
+
categories '#footer-menu h2 a' do
|
32
|
+
attributes do
|
33
|
+
{ name: page.get_one('#content .titre-principal').content }
|
34
|
+
end
|
35
|
+
|
36
|
+
categories '#content .menu-listes h2 a' do
|
37
|
+
attributes do
|
38
|
+
{ name: page.get_one('#content .titre-principal').content }
|
39
|
+
end
|
40
|
+
|
41
|
+
categories '#content .bloc_prd > a' do
|
42
|
+
attributes do
|
43
|
+
{ :name => page.get_one("#wrap-liste-produits-nav .titre-principal").content }
|
44
|
+
end
|
45
|
+
|
46
|
+
items '.infos-produit-2 > a' do
|
47
|
+
attributes do
|
48
|
+
{
|
49
|
+
:brand => page.get_one('#produit-infos .titre-principal').content,
|
50
|
+
:name => page.get_all('#produit-infos .titre-annexe, #produit-infos .titre-secondaire', Items::NAMES_SEPARATOR),
|
51
|
+
:price => page.get_one('#produit-infos .prix-actuel > span, #produit-infos .bloc-prix-promo > span.prix-promo').content.to_f,
|
52
|
+
:image => page.get_image('#produit-infos img.produit').url.to_s,
|
53
|
+
:remote_id => /\/([^\/\.]*)[^\/]*$/.match(uri.to_s)[1]
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# auchandirect/scrAPI/version.rb
|
4
|
+
#
|
5
|
+
# Copyright (c) 2010-2014 by Philippe Bourgau. All rights reserved.
|
6
|
+
#
|
7
|
+
# This library is free software; you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU Lesser General Public
|
9
|
+
# License as published by the Free Software Foundation; either
|
10
|
+
# version 3.0 of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This library is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15
|
+
# Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public
|
18
|
+
# License along with this library; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
20
|
+
# MA 02110-1301 USA
|
21
|
+
|
22
|
+
module Auchandirect
|
23
|
+
module ScrAPI
|
24
|
+
VERSION = "0.0.1"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# lib/auchandirect/scrAPI/webrick_uri_escape_monkey_patch.rb
|
4
|
+
#
|
5
|
+
# Copyright (C) 2014 by Philippe Bourgau. All rights reserved.
|
6
|
+
#
|
7
|
+
# This library is free software; you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU Lesser General Public
|
9
|
+
# License as published by the Free Software Foundation; either
|
10
|
+
# version 3.0 of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This library is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15
|
+
# Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public
|
18
|
+
# License along with this library; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
20
|
+
# MA 02110-1301 USA
|
21
|
+
|
22
|
+
require "webrick/httputils"
|
23
|
+
|
24
|
+
# monkey patch to avoid a regex uri encoding error when importing
|
25
|
+
# incompatible encoding regexp match (ASCII-8BIT regexp with UTF-8 string) (Encoding::CompatibilityError)
|
26
|
+
# .../webrick/httputils.rb:353:in `gsub'
|
27
|
+
# .../webrick/httputils.rb:353:in `_escape'
|
28
|
+
# .../webrick/httputils.rb:363:in `escape'
|
29
|
+
# from uri method
|
30
|
+
#
|
31
|
+
# I would be glad to find a better way to fix this !
|
32
|
+
|
33
|
+
module WEBrick::HTTPUtils
|
34
|
+
def self.escape(s)
|
35
|
+
URI.escape(s)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# spec/lib/auchandirect/scrAPI/cart_shared_examples.rb
|
4
|
+
#
|
5
|
+
# Copyright (C) 2011-2014 by Philippe Bourgau. All rights reserved.
|
6
|
+
#
|
7
|
+
# This library is free software; you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU Lesser General Public
|
9
|
+
# License as published by the Free Software Foundation; either
|
10
|
+
# version 3.0 of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This library is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15
|
+
# Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public
|
18
|
+
# License along with this library; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
20
|
+
# MA 02110-1301 USA
|
21
|
+
|
22
|
+
require 'spec_helper'
|
23
|
+
|
24
|
+
shared_examples_for "Any Cart" do |store_cart_class, store_url|
|
25
|
+
|
26
|
+
before :all do
|
27
|
+
@store_url = store_url
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should know its logout url" do
|
31
|
+
logout_url = store_cart_class.logout_url
|
32
|
+
|
33
|
+
expect(logout_url).to(match(URI.regexp(['http'])), "#{logout_url} is not an http url !")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should know its login url" do
|
37
|
+
expect(store_cart_class.login_url).not_to be_empty
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should know its login parameters" do
|
41
|
+
expect(store_cart_class.login_parameters(store_cart_class.valid_email, store_cart_class.valid_password)).not_to be_nil
|
42
|
+
end
|
43
|
+
|
44
|
+
{login_parameter: 'text', password_parameter: 'password'}.each do |parameter_reader, html_input_type|
|
45
|
+
it "should know its #{parameter_reader} name" do
|
46
|
+
parameter_name = store_cart_class.send(parameter_reader)
|
47
|
+
expect(parameter_name).not_to be_empty
|
48
|
+
|
49
|
+
param = store_cart_class.login_parameters("","").find{|param| param['name'] == parameter_name}
|
50
|
+
expect(param).not_to be_nil
|
51
|
+
expect(param['type']).to eq(html_input_type)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should raise when login in with an invalid account" do
|
56
|
+
expect(lambda {
|
57
|
+
store_cart_class.login("unknown-account", "wrong-password")
|
58
|
+
}).to raise_error(Auchandirect::ScrAPI::InvalidAccountError)
|
59
|
+
end
|
60
|
+
|
61
|
+
context "with a valid account" do
|
62
|
+
|
63
|
+
attr_reader :sample_item_id, :another_item_id, :store_cart_api
|
64
|
+
|
65
|
+
before(:all) do
|
66
|
+
@api = store_cart_class.login(store_cart_class.valid_email, store_cart_class.valid_password)
|
67
|
+
|
68
|
+
sample_items = extract_sample_items
|
69
|
+
sample_item = sample_items.next
|
70
|
+
@sample_item_id = sample_item.attributes[:remote_id]
|
71
|
+
@another_item_id = extract_another_item_id(sample_items, sample_item)
|
72
|
+
end
|
73
|
+
before(:each) do
|
74
|
+
@api.empty_the_cart
|
75
|
+
end
|
76
|
+
|
77
|
+
after(:all) do
|
78
|
+
@api.logout
|
79
|
+
end
|
80
|
+
|
81
|
+
# Some tests are redudant with what is item extractions, but the followings
|
82
|
+
# are clearer about what is expected from the cart
|
83
|
+
|
84
|
+
it "should set the cart value to 0 when emptying the cart" do
|
85
|
+
@api.add_to_cart(1, sample_item_id)
|
86
|
+
|
87
|
+
@api.empty_the_cart
|
88
|
+
expect(@api.cart_value).to eq 0
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should set the cart value to something greater than 0 when adding items to the cart" do
|
92
|
+
@api.empty_the_cart
|
93
|
+
|
94
|
+
@api.add_to_cart(1, sample_item_id)
|
95
|
+
expect(@api.cart_value).to be > 0
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should set the cart value to 2 times that of one item when adding 2 items" do
|
99
|
+
@api.empty_the_cart
|
100
|
+
|
101
|
+
@api.add_to_cart(1, sample_item_id)
|
102
|
+
item_price = @api.cart_value
|
103
|
+
|
104
|
+
@api.add_to_cart(1, sample_item_id)
|
105
|
+
expect(@api.cart_value).to eq 2*item_price
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should set different cart values with different items" do
|
109
|
+
sample_item_cart_value = cart_value_with_item(sample_item_id)
|
110
|
+
another_item_cart_value = cart_value_with_item(another_item_id)
|
111
|
+
|
112
|
+
expect(sample_item_cart_value).not_to eq another_item_cart_value
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should synchronize different sessions with logout login" do
|
116
|
+
@api.add_to_cart(1, sample_item_id)
|
117
|
+
|
118
|
+
api2 = store_cart_class.login(store_cart_class.valid_email, store_cart_class.valid_password)
|
119
|
+
begin
|
120
|
+
api2.empty_the_cart
|
121
|
+
ensure
|
122
|
+
api2.logout
|
123
|
+
end
|
124
|
+
|
125
|
+
@api.logout
|
126
|
+
@api = store_cart_class.login(store_cart_class.valid_email, store_cart_class.valid_password)
|
127
|
+
|
128
|
+
expect(@api.cart_value).to eq 0
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def extract_another_item_id(sample_items, sample_item)
|
134
|
+
another_item = sample_item
|
135
|
+
while sample_item.attributes[:price] == another_item.attributes[:price]
|
136
|
+
another_item = sample_items.next
|
137
|
+
end
|
138
|
+
another_item.attributes[:remote_id]
|
139
|
+
end
|
140
|
+
|
141
|
+
def extract_sample_items
|
142
|
+
extract_sample_items_from(Storexplore::Api.browse(@store_url))
|
143
|
+
end
|
144
|
+
|
145
|
+
def extract_sample_items_from(category)
|
146
|
+
items = find_available_items(category)
|
147
|
+
|
148
|
+
sub_items = nationaly_available_first(category.categories).lazy.map do |sub_category|
|
149
|
+
extract_sample_items_from(sub_category)
|
150
|
+
end
|
151
|
+
|
152
|
+
[items, sub_items].lazy.flatten
|
153
|
+
end
|
154
|
+
|
155
|
+
def find_available_items(category)
|
156
|
+
nationaly_available_first(category.items)
|
157
|
+
.find_all {|item| item_available?(item.attributes[:remote_id]) }
|
158
|
+
end
|
159
|
+
|
160
|
+
def item_available?(item_id)
|
161
|
+
@api.empty_the_cart
|
162
|
+
@api.add_to_cart(1, item_id)
|
163
|
+
item_price = @api.cart_value
|
164
|
+
return false if 0 == item_price
|
165
|
+
|
166
|
+
@api.add_to_cart(1, item_id)
|
167
|
+
return @api.cart_value == item_price * 2
|
168
|
+
end
|
169
|
+
|
170
|
+
def nationaly_available_first(elements)
|
171
|
+
# Sometimes the tests used to fail because the sample item was not available
|
172
|
+
# in the geographical region of the test user.
|
173
|
+
milks, others = elements.partition { |element| is_milk(element) }
|
174
|
+
milks + others
|
175
|
+
end
|
176
|
+
|
177
|
+
def is_milk(element)
|
178
|
+
["lait", "crème"].any? do |word|
|
179
|
+
element.title.downcase.include?(word)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def cart_value_with_item(item_id)
|
184
|
+
@api.empty_the_cart
|
185
|
+
@api.add_to_cart(1, item_id)
|
186
|
+
@api.cart_value
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|