auchandirect-scrAPI 0.0.1

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