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.
@@ -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