auchandirect-scrAPI 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|