dugway 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +3 -0
  5. data/Gemfile +1 -1
  6. data/LICENSE.txt +22 -0
  7. data/dugway.gemspec +3 -0
  8. data/lib/dugway/cart.rb +8 -12
  9. data/lib/dugway/cli/templates/Gemfile.tt +1 -1
  10. data/lib/dugway/cli/templates/gitignore.tt +1 -0
  11. data/lib/dugway/cli/templates/source/product.html +5 -3
  12. data/lib/dugway/cli/templates/source/stylesheets/cart.css.sass +8 -0
  13. data/lib/dugway/cli/templates/source/stylesheets/product.css.sass +32 -0
  14. data/lib/dugway/liquid/drops/cart_item_drop.rb +4 -0
  15. data/lib/dugway/liquid/drops/product_drop.rb +10 -6
  16. data/lib/dugway/liquid/drops/product_option_drop.rb +1 -1
  17. data/lib/dugway/liquid/drops/shipping_option_drop.rb +2 -0
  18. data/lib/dugway/liquid/tags/checkout_form.rb +1 -1
  19. data/lib/dugway/version.rb +1 -1
  20. data/spec/features/contact_form_spec.rb +43 -0
  21. data/spec/features/page_rendering_spec.rb +69 -0
  22. data/spec/features/shopping_spec.rb +38 -0
  23. data/spec/fixtures/store/products.js +1 -1
  24. data/spec/fixtures/store/store.js +1 -1
  25. data/spec/fixtures/theme/cart.html +22 -7
  26. data/spec/fixtures/theme/contact.html +37 -37
  27. data/spec/fixtures/theme/layout.html +8 -0
  28. data/spec/fixtures/theme/settings.json +1 -0
  29. data/spec/fixtures/theme/styles.css +2 -2
  30. data/spec/spec_helper.rb +8 -0
  31. data/spec/units/dugway/cart_spec.rb +204 -0
  32. data/spec/units/dugway/liquid/drops/account_drop_spec.rb +54 -0
  33. data/spec/units/dugway/liquid/drops/artist_drop_spec.rb +40 -0
  34. data/spec/units/dugway/liquid/drops/artists_drop_spec.rb +41 -0
  35. data/spec/units/dugway/liquid/drops/cart_drop_spec.rb +81 -0
  36. data/spec/units/dugway/liquid/drops/cart_item_drop_spec.rb +72 -0
  37. data/spec/units/dugway/liquid/drops/categories_drop_spec.rb +41 -0
  38. data/spec/units/dugway/liquid/drops/category_drop_spec.rb +40 -0
  39. data/spec/units/dugway/liquid/drops/contact_drop_spec.rb +124 -0
  40. data/spec/units/dugway/liquid/drops/country_drop_spec.rb +17 -0
  41. data/spec/units/dugway/liquid/drops/image_drop_spec.rb +23 -0
  42. data/spec/units/dugway/liquid/drops/page_drop_spec.rb +70 -0
  43. data/spec/units/dugway/liquid/drops/pages_drop_spec.rb +29 -0
  44. data/spec/units/dugway/liquid/drops/product_drop_spec.rb +269 -0
  45. data/spec/units/dugway/liquid/drops/product_option_drop_spec.rb +86 -0
  46. data/spec/units/dugway/liquid/drops/products_drop_spec.rb +127 -0
  47. data/spec/units/dugway/liquid/drops/shipping_option_drop_spec.rb +26 -0
  48. data/spec/units/dugway/liquid/drops/theme_drop_spec.rb +68 -0
  49. data/spec/units/dugway/store_spec.rb +27 -27
  50. data/spec/units/dugway/template_spec.rb +12 -0
  51. data/spec/units/dugway/theme_spec.rb +198 -0
  52. metadata +95 -57
  53. data/spec/units/dugway_spec.rb +0 -9
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 753ddf37dd59de0812e32500da4fcf189b9d2f89
4
+ data.tar.gz: be0e35b01e22f044c8da70bc6888647476e38cac
5
+ SHA512:
6
+ metadata.gz: 9898d404fa7127e8163d712d12448052bbb845c40b03c5382a7c8b0e0bb302514dc0c5a8918c6492533f7d876e9f359f35b09dc923a30039353a515bcb72b150
7
+ data.tar.gz: ec25ce081aee329d90e937a5d40a21dd599362416a7c0a568e520e2cb825395066888faea7f4e5bcb20373a8141d1df0c6e77d3fa5157f904e0541820aeff104
data/.gitignore CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Gemfile.lock
4
4
 
5
+ coverage
6
+
5
7
  *.gem
6
8
  *.tmproj
7
9
  *.sublime*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -1,3 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
+ - 2.0
5
+ notifications:
6
+ email: false
data/Gemfile CHANGED
@@ -1,2 +1,2 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
  gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Big Cartel, LLC
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -41,4 +41,7 @@ Gem::Specification.new do |s|
41
41
  s.add_development_dependency('rake', '~> 10.0.3')
42
42
  s.add_development_dependency('rspec', '~> 2.12.0')
43
43
  s.add_development_dependency('webmock', '~> 1.9.3')
44
+ s.add_development_dependency('json_expressions', '~> 0.8.2')
45
+ s.add_development_dependency('capybara', '~> 2.0.2')
46
+ s.add_development_dependency('simplecov', '~> 0.7.1')
44
47
  end
@@ -10,6 +10,10 @@ module Dugway
10
10
  self.items = []
11
11
  end
12
12
 
13
+ def empty?
14
+ items.empty?
15
+ end
16
+
13
17
  def item_count
14
18
  items.map { |item| item.quantity }.inject(:+) || 0
15
19
  end
@@ -53,14 +57,10 @@ module Dugway
53
57
  def update(params)
54
58
  add, adds, updates = params.delete(:add), params.delete(:adds), params.delete(:update)
55
59
  add_item(add) if add
56
- add_item(adds) if adds
60
+ add_items(adds) if adds
57
61
  update_quantities(updates) if updates
58
62
  end
59
63
 
60
- def empty?
61
- items.empty?
62
- end
63
-
64
64
  def as_json(options=nil)
65
65
  {
66
66
  :item_count => item_count,
@@ -83,7 +83,7 @@ module Dugway
83
83
  product, option = Dugway.store.product_and_option(id)
84
84
 
85
85
  if product && option
86
- item = CartItem.new
86
+ item = Item.new
87
87
  item.id = items.size + 1
88
88
  item.name = option['name'] == 'Default' ? product['name'] : "#{ product['name'] } - #{ option['name'] }"
89
89
  item.unit_price = option['price']
@@ -103,11 +103,7 @@ module Dugway
103
103
  end
104
104
 
105
105
  def add_items(adds)
106
- if adds.kind_of?(Array)
107
- adds.each { |add| add_item(add) }
108
- elsif adds.kind_of?(Hash)
109
- adds.each_pair { |key, add| add_item(add.reverse_merge(:id => key)) }
110
- end
106
+ adds.each { |add| add_item(add) }
111
107
  end
112
108
 
113
109
  def update_quantities(updates)
@@ -121,7 +117,7 @@ module Dugway
121
117
  end
122
118
  end
123
119
 
124
- CartItem = Struct.new(:id, :name, :unit_price, :quantity, :product, :option) do
120
+ Item = Struct.new(:id, :name, :unit_price, :quantity, :product, :option) do
125
121
  def price
126
122
  unit_price * quantity
127
123
  end
@@ -1,2 +1,2 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
  gem 'dugway'
@@ -1,3 +1,4 @@
1
+ .bundle
1
2
  .DS_Store
2
3
 
3
4
  build
@@ -24,12 +24,14 @@
24
24
  <h5>{{ product.default_price | money_with_sign }}{% if product.on_sale %} <em>On Sale{% endif %}</em></h5>
25
25
  <h5>Availability</h5>
26
26
 
27
- <ul>
27
+ <ul class="availability">
28
28
  {% for option in product.options %}
29
29
  <li>
30
30
  {% unless product.has_default_option %}<span>{{ option.name }}</span>{% endunless %}
31
- <span>{% if option.sold_out %}Sold Out{% else %}{{ option.inventory }}%{% endif %}</span>
32
- <div style="width:{{ option.inventory }}%"></div>
31
+ <span>{% if option.sold_out %}Sold Out{% endif %}</span>
32
+ <b>
33
+ <b style="width:{{ option.inventory }}%"></b>
34
+ </b>
33
35
  </li>
34
36
  {% endfor %}
35
37
  </ul>
@@ -1,8 +1,16 @@
1
1
  body#cart
2
2
  form
3
3
  ul
4
+ border-bottom: dashed 1px #ddd
4
5
  margin-bottom: 2em
5
6
 
7
+ ul + p
8
+ float: left
9
+
10
+ button
11
+ float: right
12
+ margin: 1.2em 0
13
+
6
14
  li
7
15
  overflow: hidden
8
16
 
@@ -8,6 +8,9 @@ body#product
8
8
  margin-right: 18px
9
9
  border: 3px solid #eee
10
10
 
11
+ img
12
+ float: left
13
+
11
14
  li.selected
12
15
  border-color: #72c29b
13
16
 
@@ -17,3 +20,32 @@ body#product
17
20
  border-right: none
18
21
  margin-left: 30px
19
22
  padding-left: 30px
23
+ width: 30%
24
+
25
+ form
26
+ div
27
+ float: left
28
+ margin-right: 5px
29
+ button
30
+ font-size: 12px
31
+
32
+ .availability
33
+ li
34
+ height: 16px
35
+ font-size: 11px
36
+ margin-bottom: 5px
37
+
38
+ span
39
+ display: block
40
+ float: left
41
+ width: 20%
42
+
43
+ > b
44
+ display: block
45
+ margin-left: 20%
46
+ width: 80%
47
+
48
+ b
49
+ background: #eee
50
+ display: block
51
+ height: 16px
@@ -5,6 +5,10 @@ module Dugway
5
5
  unit_price * quantity
6
6
  end
7
7
 
8
+ def total
9
+ price + shipping
10
+ end
11
+
8
12
  def product
9
13
  ProductDrop.new(source['product'])
10
14
  end
@@ -1,6 +1,10 @@
1
1
  module Dugway
2
2
  module Drops
3
3
  class ProductDrop < BaseDrop
4
+ def created_at
5
+ Time.parse(source['created_at'])
6
+ end
7
+
4
8
  def price
5
9
  nil # price is deprecated in favor of default_price
6
10
  end
@@ -18,7 +22,7 @@ module Dugway
18
22
  end
19
23
 
20
24
  def has_default_option
21
- @has_default_option ||= options.size == 1 && option.default
25
+ @has_default_option ||= options.size == 1 && option.name.downcase == 'default'
22
26
  end
23
27
 
24
28
  def option
@@ -30,11 +34,11 @@ module Dugway
30
34
  end
31
35
 
32
36
  def options_in_stock
33
- @options_in_stock ||= options
37
+ @options_in_stock ||= options.reject { |o| o.sold_out }
34
38
  end
35
39
 
36
40
  def shipping
37
- @shipping ||= source['shipping'].map { |o| ShippingOptionDrop.new(o.update('product' => self)) }
41
+ @shipping ||= source['shipping'].present? ? source['shipping'].map { |o| ShippingOptionDrop.new(o.update('product' => self)) } : []
38
42
  end
39
43
 
40
44
  def image
@@ -70,15 +74,15 @@ module Dugway
70
74
  end
71
75
 
72
76
  def edit_url
73
- "http://bigcartel.com"
77
+ 'http://bigcartel.com'
74
78
  end
75
79
 
76
80
  def categories
77
- @categories ||= CategoriesDrop.new(source['categories'].map { |c| CategoryDrop.new(c) }) rescue []
81
+ @categories ||= source['categories'].map { |c| CategoryDrop.new(c) } rescue []
78
82
  end
79
83
 
80
84
  def artists
81
- @artists ||= ArtistsDrop.new(source['artists'].map { |a| ArtistDrop.new(a) }) rescue []
85
+ @artists ||= source['artists'].map { |a| ArtistDrop.new(a) } rescue []
82
86
  end
83
87
 
84
88
  def css_class
@@ -2,7 +2,7 @@ module Dugway
2
2
  module Drops
3
3
  class ProductOptionDrop < BaseDrop
4
4
  def default
5
- name.downcase == 'default'
5
+ position == 1
6
6
  end
7
7
 
8
8
  def has_custom_price
@@ -5,6 +5,8 @@ module Dugway
5
5
  @country ||= CountryDrop.new(source['country'])
6
6
  end
7
7
 
8
+ # internal
9
+
8
10
  def strict
9
11
  @strict ||= product.shipping.size > 1 || product.shipping.first.country.name.present?
10
12
  end
@@ -2,7 +2,7 @@ module Dugway
2
2
  module Tags
3
3
  class CheckoutForm < ::Liquid::Block
4
4
  def render(context)
5
- %{<form id="checkout_form" name="checkout_form" method="post" action="/success"></form>}
5
+ %{<form id="checkout_form" name="checkout_form" method="post" action="/success">#{ render_all(@nodelist, context) }</form>}
6
6
  end
7
7
  end
8
8
  end
@@ -1,3 +1,3 @@
1
1
  module Dugway
2
- VERSION = "0.5.3"
2
+ VERSION = "0.5.4"
3
3
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'Contact form' do
4
+ scenario 'submitting the form' do
5
+ submit_contact_form
6
+ expect(page).to have_content('Your message has been sent')
7
+ end
8
+
9
+ scenario 'with a missing field' do
10
+ submit_contact_form(:name => '')
11
+ expect(page).to have_content('All fields are required')
12
+ end
13
+
14
+ scenario 'with an invalid email' do
15
+ submit_contact_form(:email => 'blah')
16
+ expect(page).to have_content('Invalid email address')
17
+ end
18
+
19
+ scenario 'with an invalid captcha' do
20
+ submit_contact_form(:captcha => 'blah')
21
+ expect(page).to have_content('Spam check was incorrect')
22
+ end
23
+
24
+ def submit_contact_form(fields={})
25
+ fields.reverse_merge!(
26
+ :name => 'Joe',
27
+ :email => 'joe@example.com',
28
+ :subject => 'Testing',
29
+ :message => 'Hi there',
30
+ :captcha => 'rQ9pC'
31
+ )
32
+
33
+ visit '/contact'
34
+
35
+ fill_in 'Name', :with => fields[:name]
36
+ fill_in 'Email', :with => fields[:email]
37
+ fill_in 'Subject', :with => fields[:subject]
38
+ fill_in 'Message', :with => fields[:message]
39
+ fill_in 'Spam check', :with => fields[:captcha]
40
+
41
+ click_button 'Send'
42
+ end
43
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'Page rendering' do
4
+ scenario 'home.html' do
5
+ visit '/'
6
+ expect(page).to have_content('Dugway') # layout.html
7
+ expect(page).to have_content('My Product')
8
+ expect(page).to have_content('$10.00')
9
+ end
10
+
11
+ scenario 'products.html' do
12
+ visit '/products'
13
+ expect(page).to have_content('Dugway') # layout.html
14
+ expect(page).to have_content('Products')
15
+ expect(page).to have_content('My Product')
16
+ expect(page).to have_content('$10.00')
17
+ end
18
+
19
+ scenario 'product.html' do
20
+ visit '/product/my-product'
21
+ expect(page).to have_content('Dugway') # layout.html
22
+ expect(page).to have_content('My Product')
23
+ expect(page).to have_content('$10.00')
24
+ end
25
+
26
+ scenario 'cart.html' do
27
+ visit '/cart'
28
+ expect(page).to have_content('Dugway') # layout.html
29
+ expect(page).to have_content('Cart')
30
+ expect(page).to have_content('Your cart is empty')
31
+ end
32
+
33
+ scenario 'success.html' do
34
+ visit '/success'
35
+ expect(page).to have_content('Dugway') # layout.html
36
+ expect(page).to have_content('Thank You. Your order has been placed.')
37
+ end
38
+
39
+ scenario 'contact.html' do
40
+ visit '/contact'
41
+ expect(page).to have_content('Dugway') # layout.html
42
+ expect(page).to have_content('Contact')
43
+ expect(page).to have_content('Spam check')
44
+ end
45
+
46
+ scenario 'maintenance.html' do
47
+ visit '/maintenance'
48
+ expect(page).to have_content('Please check back soon.')
49
+ end
50
+
51
+ scenario 'custom page' do
52
+ visit '/about-us'
53
+ expect(page).to have_content('Dugway') # layout.html
54
+ expect(page).to have_content('About Us')
55
+ expect(page).to have_content("We're really cool!")
56
+ end
57
+
58
+ scenario 'styles.css' do
59
+ visit '/styles.css'
60
+ expect(page).to have_content('height: 100%;') # one.css
61
+ expect(page).to have_content('color: red;') # two.css.sass
62
+ end
63
+
64
+ scenario 'scripts.js' do
65
+ visit '/scripts.js'
66
+ expect(page).to have_content("console.log('One')") # one.js
67
+ expect(page).to have_content("console.log('Two')") # two.js.coffee
68
+ end
69
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'Shopping' do
4
+ scenario 'buying a product' do
5
+ visit '/'
6
+ expect(page).to have_content('Cart ($0.00)')
7
+
8
+ add_product_to_cart
9
+ expect(page).to have_content('Cart ($10.00)')
10
+
11
+ click_button 'Checkout'
12
+ expect(page).to have_content('One moment...')
13
+
14
+ click_button 'Checkout'
15
+ expect(page).to have_content('Thank You. Your order has been placed.')
16
+ expect(page).to have_content('Cart ($0.00)')
17
+ end
18
+
19
+ scenario 'updating a cart' do
20
+ add_product_to_cart
21
+ fill_in 'item_1_qty', :with => 3
22
+ click_button 'Update'
23
+ expect(page).to have_content('Cart ($30.00)')
24
+ end
25
+
26
+ scenario 'removing a product' do
27
+ add_product_to_cart
28
+ fill_in 'item_1_qty', :with => 0
29
+ click_button 'Update'
30
+ expect(page).to have_content('Cart ($0.00)')
31
+ expect(page).to have_content('Your cart is empty')
32
+ end
33
+
34
+ def add_product_to_cart
35
+ visit '/product/my-product'
36
+ click_button 'Add to Cart'
37
+ end
38
+ end