Merge branch 'release/1.3.10'

This commit is contained in:
Nathan Chapman 2022-05-21 08:35:15 -06:00
commit 0a32eec8d6
11 changed files with 495 additions and 35 deletions

View File

@ -4,7 +4,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [1.3.10] - 2022-05-21
### Added
- Tests for almost all storefront views, exposing a couple of inconsistencies
### Fixed
- CustomerAddressUpdateView `test_func()` throwing error because addresses don't have a `customer` object
- PaymentCanceled misspelled template name
## [1.3.7] - 2022-05-19 ## [1.3.7] - 2022-05-19
### Added ### Added

View File

@ -4,6 +4,7 @@ from django.contrib.auth.models import AbstractUser
from . import STATE_CHOICES from . import STATE_CHOICES
class Address(models.Model): class Address(models.Model):
first_name = models.CharField(max_length=256, blank=True) first_name = models.CharField(max_length=256, blank=True)
last_name = models.CharField(max_length=256, blank=True) last_name = models.CharField(max_length=256, blank=True)
@ -20,6 +21,7 @@ class Address(models.Model):
def __str__(self): def __str__(self):
return f'{self.street_address_1}{self.city}' return f'{self.street_address_1}{self.city}'
class User(AbstractUser): class User(AbstractUser):
addresses = models.ManyToManyField( addresses = models.ManyToManyField(
Address, blank=True, related_name="user_addresses" Address, blank=True, related_name="user_addresses"

View File

@ -3,7 +3,7 @@
"model": "core.order", "model": "core.order",
"pk": 1, "pk": 1,
"fields": { "fields": {
"customer": null, "customer": 1,
"status": "unfulfilled", "status": "unfulfilled",
"billing_address": null, "billing_address": null,
"shipping_address": 1, "shipping_address": 1,
@ -19,7 +19,7 @@
"model": "core.order", "model": "core.order",
"pk": 2, "pk": 2,
"fields": { "fields": {
"customer": null, "customer": 1,
"status": "unfulfilled", "status": "unfulfilled",
"billing_address": null, "billing_address": null,
"shipping_address": 1, "shipping_address": 1,
@ -35,7 +35,7 @@
"model": "core.order", "model": "core.order",
"pk": 3, "pk": 3,
"fields": { "fields": {
"customer": null, "customer": 2,
"status": "unfulfilled", "status": "unfulfilled",
"billing_address": null, "billing_address": null,
"shipping_address": 1, "shipping_address": 1,

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

View File

@ -0,0 +1,37 @@
from decimal import Decimal
from django.test import TestCase
from measurement.measures import Weight
from core.models import (
Product,
ProductPhoto,
Coupon,
ShippingMethod,
Order,
Transaction,
OrderLine,
TrackingNumber,
)
class ProductModelTest(TestCase):
@classmethod
def setUpTestData(cls):
Product.objects.create(
name='Pantomime',
subtitle='Very Dark French Roast',
description='Our darkest drip. A blend of five different beans roasted two ways. Organic Africa, Indonesia, and South and Central America.',
sku='565656',
price=Decimal('15.00'),
weight=Weight(oz=16),
visible_in_listings=True,
sorting=1,
)
def test_get_absolute_url(self):
product = Product.objects.get(pk=1)
self.assertEqual(
product.get_absolute_url(),
'/dashboard/products/1/'
)

View File

View File

@ -12,13 +12,42 @@ from accounts.models import User, Address
from core.models import Product, Order, Coupon from core.models import Product, Order, Coupon
from core import CoffeeGrind from core import CoffeeGrind
from storefront.forms import AddressForm, OrderCreateForm from storefront.forms import AddressForm, OrderCreateForm
from storefront.views import OrderCreateView, CheckoutAddressView from storefront.views import (
CartView, CartAddProductView, CartUpdateProductView, CouponApplyView,
ProductListView, ProductDetailView,
CheckoutAddressView, OrderCreateView,
paypal_order_transaction_capture, paypal_webhook_endpoint,
PaymentDoneView, PaymentCanceledView,
CustomerDetailView, CustomerUpdateView, OrderDetailView,
CustomerAddressCreateView, CustomerAddressUpdateView,
AboutView, FairTradeView, ReviewListView, ContactFormView,
)
from storefront.cart import Cart from storefront.cart import Cart
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class CheckoutAddressViewTests(TestCase): class CartViewTest(TestCase):
fixtures = ['products.json']
def setUp(self):
self.client = Client()
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/cart/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(reverse('storefront:cart-detail'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('storefront:cart-detail'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/cart_detail.html')
class CheckoutAddressViewTest(TestCase):
def setUp(self): def setUp(self):
self.client = Client() self.client = Client()
@ -33,7 +62,7 @@ class CheckoutAddressViewTests(TestCase):
self.assertTrue(isinstance(response.context['form'], AddressForm)) self.assertTrue(isinstance(response.context['form'], AddressForm))
class OrderCreateViewTests(TestCase): class OrderCreateViewTest(TestCase):
fixtures = ['accounts.json', 'coupons.json'] fixtures = ['accounts.json', 'coupons.json']
@classmethod @classmethod
@ -54,8 +83,6 @@ class OrderCreateViewTests(TestCase):
def setUp(self): def setUp(self):
self.client = Client() self.client = Client()
def test_used_coupon_creates_error_on_checkout(self):
session = self.client.session session = self.client.session
session['shipping_address'] = { session['shipping_address'] = {
'first_name': 'Nathan', 'first_name': 'Nathan',
@ -67,6 +94,27 @@ class OrderCreateViewTests(TestCase):
'state': 'UT', 'state': 'UT',
'postal_code': '84341' 'postal_code': '84341'
} }
session.save()
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/checkout/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(
reverse('storefront:order-create')
)
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(
reverse('storefront:order-create')
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/order_form.html')
def test_used_coupon_creates_error_on_checkout(self):
session = self.client.session
session['coupon_code'] = 'MAY2022' session['coupon_code'] = 'MAY2022'
session.save() session.save()
@ -76,3 +124,323 @@ class OrderCreateViewTests(TestCase):
self.assertTrue(self.client.session.get('shipping_address')) self.assertTrue(self.client.session.get('shipping_address'))
self.assertTemplateUsed(response, 'storefront/order_form.html') self.assertTemplateUsed(response, 'storefront/order_form.html')
self.assertContains(response, 'Coupon already used', status_code=200) self.assertContains(response, 'Coupon already used', status_code=200)
class ProductListViewTest(TestCase):
fixtures = ['products.json']
def setUp(self):
self.client = Client()
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(reverse('storefront:product-list'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('storefront:product-list'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/product_list.html')
class ProductDetailViewTest(TestCase):
fixtures = ['products.json']
def setUp(self):
self.client = Client()
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/products/1/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(
reverse('storefront:product-detail', kwargs={'pk': 1})
)
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(
reverse('storefront:product-detail', kwargs={'pk': 1})
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/product_detail.html')
class CheckoutAddressViewTest(TestCase):
fixtures = ['products.json']
def setUp(self):
self.client = Client()
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/checkout/address/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(reverse('storefront:checkout-address'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('storefront:checkout-address'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/checkout_address.html')
class OrderCreateViewTest(TestCase):
fixtures = ['products.json']
def setUp(self):
self.client = Client()
class PaymentDoneViewTest(TestCase):
fixtures = ['products.json']
def setUp(self):
self.client = Client()
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/done/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(reverse('storefront:payment-done'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('storefront:payment-done'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/payment_done.html')
class PaymentCanceledViewTest(TestCase):
fixtures = ['products.json']
def setUp(self):
self.client = Client()
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/canceled/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(reverse('storefront:payment-canceled'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('storefront:payment-canceled'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/payment_canceled.html')
class CustomerDetailViewTest(TestCase):
fixtures = ['products.json', 'accounts.json']
def setUp(self):
self.client = Client()
self.user = User.objects.get(pk=1)
self.client.force_login(self.user)
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/customers/1/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(
reverse('storefront:customer-detail', kwargs={'pk': 1})
)
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(
reverse('storefront:customer-detail', kwargs={'pk': 1})
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/customer_detail.html')
class CustomerUpdateViewTest(TestCase):
fixtures = ['products.json', 'accounts.json']
def setUp(self):
self.client = Client()
self.user = User.objects.get(pk=1)
self.client.force_login(self.user)
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/customers/1/update/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(
reverse('storefront:customer-update', kwargs={'pk': 1})
)
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(
reverse('storefront:customer-update', kwargs={'pk': 1})
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/customer_form.html')
class OrderDetailViewTest(TestCase):
fixtures = ['products.json', 'accounts.json', 'orders.json']
def setUp(self):
self.client = Client()
self.user = User.objects.get(pk=1)
self.client.force_login(self.user)
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/customers/1/orders/1/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(
reverse('storefront:order-detail', kwargs={'pk': 1, 'order_pk': 1})
)
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(
reverse('storefront:order-detail', kwargs={'pk': 1, 'order_pk': 1})
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/order_detail.html')
class CustomerAddressCreateViewTest(TestCase):
fixtures = ['products.json', 'accounts.json']
def setUp(self):
self.client = Client()
self.user = User.objects.get(pk=1)
self.client.force_login(self.user)
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/customers/1/addresses/new/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(
reverse('storefront:customer-address-create', kwargs={'pk': 1})
)
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(
reverse('storefront:customer-address-create', kwargs={'pk': 1})
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(
response, 'storefront/address_create_form.html'
)
class CustomerAddressUpdateViewTest(TestCase):
fixtures = ['products.json', 'accounts.json']
def setUp(self):
self.client = Client()
self.user = User.objects.get(pk=1)
self.client.force_login(self.user)
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/customers/1/addresses/1/update/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(
reverse('storefront:address-update', kwargs={
'pk': 1, 'address_pk': 1
})
)
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(
reverse('storefront:address-update', kwargs={
'pk': 1, 'address_pk': 1}
)
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/address_form.html')
class AboutViewTest(TestCase):
def setUp(self):
self.client = Client()
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/about/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(reverse('storefront:about'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('storefront:about'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/about.html')
class FairTradeViewTest(TestCase):
def setUp(self):
self.client = Client()
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/fair-trade/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(reverse('storefront:fair-trade'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('storefront:fair-trade'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/fairtrade.html')
class ReviewListViewTest(TestCase):
def setUp(self):
self.client = Client()
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/reviews/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(reverse('storefront:reviews'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('storefront:reviews'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/reviews.html')
class ContactFormViewTest(TestCase):
def setUp(self):
self.client = Client()
def test_view_url_exists_at_desired_location(self):
response = self.client.get('/contact/')
self.assertEqual(response.status_code, 200)
def test_view_url_accessible_by_name(self):
response = self.client.get(reverse('storefront:contact'))
self.assertEqual(response.status_code, 200)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('storefront:contact'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'storefront/contact_form.html')

View File

@ -11,30 +11,80 @@ urlpatterns = [
path('products/<int:pk>/', include([ path('products/<int:pk>/', include([
path('', views.ProductDetailView.as_view(), name='product-detail'), path('', views.ProductDetailView.as_view(), name='product-detail'),
])), ])),
path('cart/', views.CartView.as_view(), name='cart-detail'), path('cart/', views.CartView.as_view(), name='cart-detail'),
path('cart/<int:pk>/add/', views.CartAddProductView.as_view(), name='cart-add'), path(
path('cart/<int:pk>/update/<slug:grind>/', views.CartUpdateProductView.as_view(), name='cart-update'), 'cart/<int:pk>/add/',
path('cart/<int:pk>/remove/<slug:grind>/', views.cart_remove_product_view, name='cart-remove'), views.CartAddProductView.as_view(),
name='cart-add'
path('coupon/apply/', views.CouponApplyView.as_view(), name='coupon-apply'), ),
path(
path('paypal/order/<slug:transaction_id>/capture/', views.paypal_order_transaction_capture, name='paypal-capture'), 'cart/<int:pk>/update/<slug:grind>/',
path('paypal/webhooks/', views.paypal_webhook_endpoint, name='paypal-webhook'), views.CartUpdateProductView.as_view(),
name='cart-update',
path('checkout/address/', views.CheckoutAddressView.as_view(), name='checkout-address'), ),
path(
'cart/<int:pk>/remove/<slug:grind>/',
views.cart_remove_product_view,
name='cart-remove',
),
path(
'coupon/apply/',
views.CouponApplyView.as_view(),
name='coupon-apply'
),
path(
'paypal/order/<slug:transaction_id>/capture/',
views.paypal_order_transaction_capture,
name='paypal-capture',
),
path(
'paypal/webhooks/',
views.paypal_webhook_endpoint,
name='paypal-webhook'
),
path(
'checkout/address/',
views.CheckoutAddressView.as_view(),
name='checkout-address',
),
path('checkout/', views.OrderCreateView.as_view(), name='order-create'), path('checkout/', views.OrderCreateView.as_view(), name='order-create'),
path('done/', views.PaymentDoneView.as_view(), name='payment-done'), path('done/', views.PaymentDoneView.as_view(), name='payment-done'),
path('canceled/', views.PaymentCanceledView.as_view(), name='payment-canceled'), path(
'canceled/',
views.PaymentCanceledView.as_view(),
name='payment-canceled'
),
path('customers/<int:pk>/', include([ path('customers/<int:pk>/', include([
path('', views.CustomerDetailView.as_view(), name='customer-detail'), path(
path('update/', views.CustomerUpdateView.as_view(), name='customer-update'), '',
# path('delete/', views.CustomerDeleteView.as_view(), name='customer-delete'), views.CustomerDetailView.as_view(),
name='customer-detail'
path('orders/<int:order_pk>/', views.OrderDetailView.as_view(), name='order-detail'), ),
path('addresses/new/', views.CustomerAddressCreateView.as_view(), name='customer-address-create'), path(
path('addresses/<int:address_pk>/update/', views.CustomerAddressUpdateView.as_view(), name='address-update'), 'update/',
])), views.CustomerUpdateView.as_view(),
name='customer-update',
),
# path(
# 'delete/',
# views.CustomerDeleteView.as_view(),
# name='customer-delete'
# ),
path(
'orders/<int:order_pk>/',
views.OrderDetailView.as_view(),
name='order-detail',
),
path(
'addresses/new/',
views.CustomerAddressCreateView.as_view(),
name='customer-address-create',
),
path(
'addresses/<int:address_pk>/update/',
views.CustomerAddressUpdateView.as_view(),
name='address-update',
)
]))
] ]

View File

@ -422,7 +422,7 @@ class CustomerAddressUpdateView(
raise_exception = True raise_exception = True
def test_func(self): def test_func(self):
return self.request.user.pk == self.get_object().customer.pk return self.request.user.pk == self.kwargs['pk']
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)