workarea-save_for_later 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +20 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  4. data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. data/.gitignore +25 -0
  7. data/CHANGELOG.md +17 -0
  8. data/CODE_OF_CONDUCT.md +3 -0
  9. data/CONTRIBUTING.md +3 -0
  10. data/Gemfile +17 -0
  11. data/LICENSE +52 -0
  12. data/README.md +51 -0
  13. data/Rakefile +60 -0
  14. data/app/assets/stylesheets/workarea/storefront/save_for_later/components/_product_prices.scss +5 -0
  15. data/app/controllers/workarea/storefront/cart_items_controller.decorator +12 -0
  16. data/app/controllers/workarea/storefront/current_saved_list.rb +54 -0
  17. data/app/controllers/workarea/storefront/saved_list_items_controller.rb +55 -0
  18. data/app/helpers/.keep +0 -0
  19. data/app/helpers/workarea/storefront/saved_lists_helper.rb +13 -0
  20. data/app/models/workarea/saved_list.rb +27 -0
  21. data/app/models/workarea/saved_list/item.rb +14 -0
  22. data/app/view_models/workarea/storefront/saved_list_item_view_model.rb +45 -0
  23. data/app/view_models/workarea/storefront/saved_list_view_model.rb +19 -0
  24. data/app/views/workarea/storefront/carts/_save_for_later_button.html.haml +8 -0
  25. data/app/views/workarea/storefront/carts/_saved_for_later.html.haml +52 -0
  26. data/bin/rails +20 -0
  27. data/config/initializers/appends.rb +14 -0
  28. data/config/initializers/config.rb +3 -0
  29. data/config/locales/en.yml +14 -0
  30. data/config/routes.rb +5 -0
  31. data/lib/workarea/save_for_later.rb +11 -0
  32. data/lib/workarea/save_for_later/engine.rb +13 -0
  33. data/lib/workarea/save_for_later/version.rb +5 -0
  34. data/test/dummy/.ruby-version +1 -0
  35. data/test/dummy/Rakefile +6 -0
  36. data/test/dummy/app/assets/config/manifest.js +3 -0
  37. data/test/dummy/app/assets/images/.keep +0 -0
  38. data/test/dummy/app/assets/javascripts/application.js +14 -0
  39. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  40. data/test/dummy/app/controllers/application_controller.rb +2 -0
  41. data/test/dummy/app/controllers/concerns/.keep +0 -0
  42. data/test/dummy/app/helpers/application_helper.rb +2 -0
  43. data/test/dummy/app/jobs/application_job.rb +2 -0
  44. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  45. data/test/dummy/app/models/concerns/.keep +0 -0
  46. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  47. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  48. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  49. data/test/dummy/bin/bundle +3 -0
  50. data/test/dummy/bin/rails +4 -0
  51. data/test/dummy/bin/rake +4 -0
  52. data/test/dummy/bin/setup +36 -0
  53. data/test/dummy/bin/update +31 -0
  54. data/test/dummy/bin/yarn +11 -0
  55. data/test/dummy/config.ru +5 -0
  56. data/test/dummy/config/application.rb +29 -0
  57. data/test/dummy/config/boot.rb +5 -0
  58. data/test/dummy/config/cable.yml +10 -0
  59. data/test/dummy/config/environment.rb +5 -0
  60. data/test/dummy/config/environments/development.rb +61 -0
  61. data/test/dummy/config/environments/production.rb +94 -0
  62. data/test/dummy/config/environments/test.rb +45 -0
  63. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  64. data/test/dummy/config/initializers/assets.rb +14 -0
  65. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  66. data/test/dummy/config/initializers/content_security_policy.rb +25 -0
  67. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  68. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  69. data/test/dummy/config/initializers/inflections.rb +16 -0
  70. data/test/dummy/config/initializers/mime_types.rb +4 -0
  71. data/test/dummy/config/initializers/workarea.rb +5 -0
  72. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  73. data/test/dummy/config/locales/en.yml +33 -0
  74. data/test/dummy/config/puma.rb +34 -0
  75. data/test/dummy/config/routes.rb +5 -0
  76. data/test/dummy/config/secrets.yml +32 -0
  77. data/test/dummy/config/spring.rb +6 -0
  78. data/test/dummy/config/storage.yml +34 -0
  79. data/test/dummy/db/seeds.rb +2 -0
  80. data/test/dummy/lib/assets/.keep +0 -0
  81. data/test/dummy/log/.keep +0 -0
  82. data/test/factories/workarea/saved_list.rb +13 -0
  83. data/test/integration/workarea/storefront/cart_items_save_for_later_integration_test.rb +46 -0
  84. data/test/integration/workarea/storefront/current_saved_list_integration_test.rb +62 -0
  85. data/test/integration/workarea/storefront/saved_list_items_integration_test.rb +107 -0
  86. data/test/models/workarea/saved_list_test.rb +40 -0
  87. data/test/system/workarea/storefront/save_for_later_system_test.rb +59 -0
  88. data/test/teaspoon_env.rb +6 -0
  89. data/test/test_helper.rb +10 -0
  90. data/workarea-save_for_later.gemspec +23 -0
  91. metadata +146 -0
@@ -0,0 +1,34 @@
1
+ # Puma can serve each request in a thread from an internal thread pool.
2
+ # The `threads` method setting takes two numbers: a minimum and maximum.
3
+ # Any libraries that use thread pools should be configured to match
4
+ # the maximum value specified for Puma. Default is set to 5 threads for minimum
5
+ # and maximum; this matches the default thread size of Active Record.
6
+ #
7
+ threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8
+ threads threads_count, threads_count
9
+
10
+ # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
11
+ #
12
+ port ENV.fetch("PORT") { 3000 }
13
+
14
+ # Specifies the `environment` that Puma will run in.
15
+ #
16
+ environment ENV.fetch("RAILS_ENV") { "development" }
17
+
18
+ # Specifies the number of `workers` to boot in clustered mode.
19
+ # Workers are forked webserver processes. If using threads and workers together
20
+ # the concurrency of the application would be max `threads` * `workers`.
21
+ # Workers do not work on JRuby or Windows (both of which do not support
22
+ # processes).
23
+ #
24
+ # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
25
+
26
+ # Use the `preload_app!` method when specifying a `workers` number.
27
+ # This directive tells Puma to first boot the application and load code
28
+ # before forking the application. This takes advantage of Copy On Write
29
+ # process behavior so workers use less memory.
30
+ #
31
+ # preload_app!
32
+
33
+ # Allow puma to be restarted by `rails restart` command.
34
+ plugin :tmp_restart
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+ mount Workarea::Core::Engine => '/'
3
+ mount Workarea::Admin::Engine => '/admin', as: 'admin'
4
+ mount Workarea::Storefront::Engine => '/', as: 'storefront'
5
+ end
@@ -0,0 +1,32 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key is used for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+
6
+ # Make sure the secret is at least 30 characters and all random,
7
+ # no regular words or you'll be exposed to dictionary attacks.
8
+ # You can use `rails secret` to generate a secure secret key.
9
+
10
+ # Make sure the secrets in this file are kept private
11
+ # if you're sharing your code publicly.
12
+
13
+ # Shared secrets are available across all environments.
14
+
15
+ # shared:
16
+ # api_key: a1B2c3D4e5F6
17
+
18
+ # Environmental secrets are only available for that specific environment.
19
+
20
+ development:
21
+ secret_key_base: d3364c9c3fe096e40cc6a7760d7a8a6ce5c77d14740aa93cd5a22fb0ba93399e2ac37f3389beafa9972baea954a11e212d9e758403118da6b81cf63586010975
22
+
23
+ test:
24
+ secret_key_base: 0269072d24b9571bb0ec5da912551468faebdea32ed5acccec913c16d6ff09f5420f229db0740a40d095f85014d56e357f629d07b43e95d011cac5b67e657a37
25
+
26
+ # Do not keep production secrets in the unencrypted secrets file.
27
+ # Instead, either read values from the environment.
28
+ # Or, use `bin/rails secrets:setup` to configure encrypted secrets
29
+ # and move the `production:` environment over there.
30
+
31
+ production:
32
+ secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
@@ -0,0 +1,6 @@
1
+ %w[
2
+ .ruby-version
3
+ .rbenv-vars
4
+ tmp/restart.txt
5
+ tmp/caching-dev.txt
6
+ ].each { |path| Spring.watch(path) }
@@ -0,0 +1,34 @@
1
+ test:
2
+ service: Disk
3
+ root: <%= Rails.root.join("tmp/storage") %>
4
+
5
+ local:
6
+ service: Disk
7
+ root: <%= Rails.root.join("storage") %>
8
+
9
+ # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
10
+ # amazon:
11
+ # service: S3
12
+ # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
13
+ # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
14
+ # region: us-east-1
15
+ # bucket: your_own_bucket
16
+
17
+ # Remember not to checkin your GCS keyfile to a repository
18
+ # google:
19
+ # service: GCS
20
+ # project: your_project
21
+ # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
22
+ # bucket: your_own_bucket
23
+
24
+ # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
25
+ # microsoft:
26
+ # service: AzureStorage
27
+ # storage_account_name: your_account_name
28
+ # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
29
+ # container: your_container_name
30
+
31
+ # mirror:
32
+ # service: Mirror
33
+ # primary: local
34
+ # mirrors: [ amazon, google, microsoft ]
@@ -0,0 +1,2 @@
1
+ require 'workarea/seeds'
2
+ Workarea::Seeds.run
File without changes
File without changes
@@ -0,0 +1,13 @@
1
+ require 'workarea/testing/factories'
2
+
3
+ module Workarea
4
+ module Factories
5
+ module SavedList
6
+ Factories.add(SavedList)
7
+
8
+ def create_saved_list(attributes = {})
9
+ Workarea::SavedList.create!(attributes)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Storefront
5
+ class CartItemsSaveForLaterIntegrationTest < Workarea::IntegrationTest
6
+ setup :set_product
7
+
8
+ def set_product
9
+ @product = create_product(
10
+ name: 'Integration Product',
11
+ variants: [
12
+ { sku: 'SKU1', regular: 5.to_m },
13
+ { sku: 'SKU2', regular: 6.to_m }
14
+ ]
15
+ )
16
+ end
17
+
18
+ def test_can_add_an_item
19
+ list = create_saved_list(
20
+ items: [{ product_id: @product.id, sku: @product.skus.first }]
21
+ )
22
+ item = list.items.first
23
+ cookies[:saved_list_id] = list.id.to_s
24
+
25
+ post storefront.cart_items_path,
26
+ params: {
27
+ product_id: item.product_id,
28
+ sku: item.sku,
29
+ quantity: item.quantity,
30
+ saved_list_item_id: item.id
31
+ }
32
+
33
+ order = Order.first
34
+ assert_equal(@product.id, order.items.first.product_id)
35
+ assert_equal(@product.skus.first, order.items.first.sku)
36
+ assert_equal(1, order.items.first.quantity)
37
+ assert_equal(5.to_m, order.items.first.total_price)
38
+
39
+ list.reload
40
+ assert_equal(0, list.items.count)
41
+
42
+ assert_redirected_to(storefront.cart_path)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Storefront
5
+ class CurrentSavedListIntegrationTest < Workarea::IntegrationTest
6
+ setup :product, :user
7
+
8
+ def product
9
+ @product ||= create_product
10
+ end
11
+
12
+ def user
13
+ @user ||= create_user(
14
+ email: 'test@workarea.com',
15
+ password: 'W3bl1nc!'
16
+ )
17
+ end
18
+
19
+ def test_current_saved_list
20
+ post storefront.cart_items_path,
21
+ params: {
22
+ product_id: product.id,
23
+ sku: product.skus.first,
24
+ quantity: 3,
25
+ }
26
+
27
+ get storefront.cart_path
28
+
29
+ refute(cookies[:saved_list_id].present?)
30
+
31
+ order = Order.first
32
+ item = order.items.first
33
+
34
+ post storefront.saved_list_items_path,
35
+ params: {
36
+ product_id: item.product_id,
37
+ sku: item.sku,
38
+ quantity: item.quantity,
39
+ cart_item_id: item.id
40
+ }
41
+
42
+ assert(cookies[:saved_list_id].present?)
43
+
44
+ list = SavedList.find(cookies[:saved_list_id])
45
+ assert_equal(1, list.items.count)
46
+
47
+ post storefront.login_path,
48
+ params: {
49
+ email: 'test@workarea.com',
50
+ password: 'W3bl1nc!'
51
+ }
52
+
53
+ refute(cookies[:saved_list_id].present?)
54
+
55
+ assert_raises(Mongoid::Errors::DocumentNotFound) { list.reload }
56
+
57
+ list = SavedList.find(user.id.to_s)
58
+ assert_equal(1, list.items.count)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,107 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Storefront
5
+ class SavedListItemsIntegrationTest < Workarea::IntegrationTest
6
+ include CatalogCustomizationTestClass
7
+
8
+ setup :product, :saved_list
9
+
10
+ def product
11
+ @product ||= create_product(customizations: 'foo_cust')
12
+ end
13
+
14
+ def saved_list
15
+ @saved_list ||= create_saved_list.tap do |list|
16
+ cookies[:saved_list_id] = list.id.to_s
17
+ end
18
+ end
19
+
20
+ def test_create
21
+ post storefront.saved_list_items_path,
22
+ params: {
23
+ product_id: product.id,
24
+ sku: product.skus.first,
25
+ quantity: 2,
26
+ customizations: { foo: 'test', bar: 'baz' }.to_json
27
+ }
28
+
29
+ assert_redirected_to(storefront.cart_path)
30
+
31
+ saved_list.reload
32
+ item = saved_list.items.first
33
+ assert_equal(product.id, item.product_id)
34
+ assert_equal(product.skus.first, item.sku)
35
+ assert_equal(2, item.quantity)
36
+ assert_equal({ 'foo' => 'test', 'bar' => 'baz' }, item.customizations)
37
+ end
38
+
39
+ def test_create_from_order_item
40
+ post storefront.cart_items_path,
41
+ params: {
42
+ product_id: product.id,
43
+ sku: product.skus.first,
44
+ quantity: 3,
45
+ customizations: { foo: 'test', bar: 'baz' }
46
+ }
47
+
48
+ order = Order.first
49
+ item = order.items.first
50
+
51
+ post storefront.saved_list_items_path,
52
+ params: {
53
+ product_id: item.product_id,
54
+ sku: item.sku,
55
+ quantity: item.quantity,
56
+ customizations: { foo: 'test', bar: 'baz' }.to_json,
57
+ cart_item_id: item.id
58
+ }
59
+
60
+ assert_redirected_to(storefront.cart_path)
61
+
62
+ saved_list.reload
63
+ item = saved_list.items.first
64
+ assert_equal(product.id, item.product_id)
65
+ assert_equal(product.skus.first, item.sku)
66
+ assert_equal(3, item.quantity)
67
+ assert_equal({ 'foo' => 'test', 'bar' => 'baz' }, item.customizations)
68
+
69
+ order.reload
70
+ assert_equal(0, order.items.count)
71
+ end
72
+
73
+ def test_create_with_invalid_customizations
74
+ post storefront.saved_list_items_path,
75
+ params: {
76
+ product_id: product.id,
77
+ sku: product.skus.first,
78
+ quantity: 2,
79
+ customizations: { foo: 'test' }.to_json
80
+ }
81
+
82
+ assert_redirected_to(storefront.cart_path)
83
+ assert_equal(
84
+ t('workarea.storefront.saved_lists.flash_messages.error'),
85
+ flash[:error]
86
+ )
87
+
88
+ saved_list.reload
89
+ assert_equal(0, saved_list.items.count)
90
+ end
91
+
92
+ def test_destroy
93
+ saved_list.items.create!(
94
+ product_id: product.id,
95
+ sku: product.skus.first,
96
+ )
97
+
98
+ delete storefront.saved_list_item_path(saved_list.items.first.id)
99
+
100
+ assert_redirected_to(storefront.cart_path)
101
+
102
+ saved_list.reload
103
+ assert_equal(0, saved_list.items.count)
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,40 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ class SavedListTest < TestCase
5
+ def test_add_item
6
+ product = create_product
7
+
8
+ list = SavedList.new
9
+
10
+ list.add_item(product_id: 'PROD1', sku: 'SKU1')
11
+ assert_equal(1, list.items.count)
12
+
13
+ item = list.items.first
14
+ assert_equal('PROD1', item.product_id)
15
+ assert_equal('SKU1', item.sku)
16
+ assert_equal(1, item.quantity)
17
+
18
+ list.add_item(
19
+ product_id: 'PROD1',
20
+ sku: 'SKU2',
21
+ quantity: 3,
22
+ customizations: { 'foo' => 'bar' }
23
+ )
24
+ assert_equal(2, list.items.count)
25
+
26
+ item = list.items.where(sku: 'SKU2').first
27
+ assert_equal('PROD1', item.product_id)
28
+ assert_equal('SKU2', item.sku)
29
+ assert_equal(3, item.quantity)
30
+ assert_equal({ 'foo' => 'bar' }, item.customizations)
31
+
32
+ list.add_item(product_id: 'PROD1', sku: 'SKU1', quantity: 4)
33
+
34
+ item = list.items.where(sku: 'SKU1').first
35
+ assert_equal('PROD1', item.product_id)
36
+ assert_equal('SKU1', item.sku)
37
+ assert_equal(5, item.quantity)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,59 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Storefront
5
+ class SaveForLaterSystemTest < Workarea::SystemTest
6
+ def test_managing_saved_list
7
+ product = create_product
8
+ inventory = create_inventory(
9
+ id: product.skus.first,
10
+ policy: :standard,
11
+ available: 10
12
+ )
13
+
14
+ visit storefront.product_path(product)
15
+ click_button t('workarea.storefront.products.add_to_cart')
16
+
17
+ visit storefront.cart_path
18
+
19
+ assert(page.has_no_content?(t('workarea.storefront.carts.empty')))
20
+ assert(page.has_no_content?(t('workarea.storefront.saved_lists.title')))
21
+ assert(page.has_content?(product.name))
22
+ assert(page.has_content?(product.skus.first))
23
+
24
+ click_button t('workarea.storefront.carts.save_for_later')
25
+
26
+ assert(page.has_content?('Success'))
27
+
28
+ assert(page.has_content?(t('workarea.storefront.carts.empty')))
29
+ assert(page.has_content?(t('workarea.storefront.saved_lists.title')))
30
+ assert(page.has_content?(product.name))
31
+ assert(page.has_content?(product.skus.first))
32
+ assert(page.has_content?(t('workarea.storefront.products.in_stock')))
33
+
34
+ click_button t('workarea.storefront.saved_lists.move_to_cart')
35
+
36
+ assert(page.has_no_content?(t('workarea.storefront.carts.empty')))
37
+ assert(page.has_no_content?(t('workarea.storefront.saved_lists.title')))
38
+ assert(page.has_content?(product.name))
39
+ assert(page.has_content?(product.skus.first))
40
+
41
+ inventory.update(available: 0)
42
+
43
+ click_button t('workarea.storefront.carts.save_for_later')
44
+
45
+ assert(page.has_content?('Success'))
46
+ assert(page.has_content?(t('workarea.storefront.products.out_of_stock')))
47
+ assert(page.has_no_content?(t('workarea.storefront.saved_lists.move_to_cart')))
48
+ assert(page.has_content?(t('workarea.storefront.products.unavailable')))
49
+
50
+ click_link t('workarea.storefront.saved_lists.remove')
51
+
52
+ assert(page.has_content?('Success'))
53
+
54
+ assert(page.has_content?(t('workarea.storefront.carts.empty')))
55
+ assert(page.has_no_content?(t('workarea.storefront.saved_lists.title')))
56
+ end
57
+ end
58
+ end
59
+ end