135 lines
5.5 KiB
Python
135 lines
5.5 KiB
Python
import json
|
|
from io import BytesIO
|
|
|
|
from django.contrib.auth.models import User
|
|
from django.core.files.base import ContentFile
|
|
from django.test import TestCase
|
|
from django.urls import reverse
|
|
from PIL import Image
|
|
|
|
from shop.models import Product, ProductImage, ProductVariant
|
|
from shop.tests.mixins import CreateProductsMixin
|
|
|
|
|
|
class TestBackofficeHtmxContract(TestCase, CreateProductsMixin):
|
|
def setUp(self):
|
|
self.superuser = User.objects.create_superuser('vader', 'vader@empire.com', 'ihatesand')
|
|
self.client.force_login(self.superuser)
|
|
self.product = self.create_product()
|
|
|
|
def test_htmx_get_create_form_returns_fragment_not_full_page(self):
|
|
response = self.client.get(reverse('backoffice:product_create'), HTTP_HX_REQUEST='true')
|
|
assert response.status_code == 200
|
|
body = response.content.decode()
|
|
assert '<html' not in body
|
|
assert 'Añadir producto' in body
|
|
|
|
def test_htmx_create_success_returns_204_and_triggers_modal_close_and_refresh(self):
|
|
response = self.client.post(
|
|
reverse('backoffice:product_create'),
|
|
{
|
|
'sku': 'HTMX-1',
|
|
'name': 'Producto htmx',
|
|
'description': '',
|
|
'stock': '0',
|
|
'categories': [],
|
|
'tags': [],
|
|
},
|
|
HTTP_HX_REQUEST='true',
|
|
)
|
|
assert response.status_code == 204
|
|
trigger = json.loads(response['HX-Trigger'])
|
|
assert trigger == {'backoffice:modal-close': True, 'backoffice:list-changed': True}
|
|
assert Product.objects.filter(sku='HTMX-1').exists()
|
|
|
|
def test_htmx_create_invalid_returns_200_with_errors_not_204(self):
|
|
response = self.client.post(
|
|
reverse('backoffice:product_create'),
|
|
{'sku': '', 'name': '', 'description': '', 'stock': '0', 'categories': [], 'tags': []},
|
|
HTTP_HX_REQUEST='true',
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'HX-Trigger' not in response
|
|
|
|
def test_non_htmx_create_still_redirects(self):
|
|
response = self.client.post(
|
|
reverse('backoffice:product_create'),
|
|
{
|
|
'sku': 'PLAIN-1',
|
|
'name': 'Producto normal',
|
|
'description': '',
|
|
'stock': '0',
|
|
'categories': [],
|
|
'tags': [],
|
|
},
|
|
)
|
|
assert response.status_code == 302
|
|
assert 'HX-Trigger' not in response
|
|
|
|
def test_htmx_variant_create_triggers_refresh(self):
|
|
size_m = self.create_attribute_value('Talla', 'M')
|
|
|
|
response = self.client.post(
|
|
reverse('backoffice:product_variant_create', args=[self.product.pk]),
|
|
{'sku': 'HTMX-V1', 'stock': '5', 'attribute_values': [size_m.pk]},
|
|
HTTP_HX_REQUEST='true',
|
|
)
|
|
assert response.status_code == 204
|
|
trigger = json.loads(response['HX-Trigger'])
|
|
assert trigger['backoffice:modal-close'] is True
|
|
assert trigger['backoffice:list-changed'] is True
|
|
assert ProductVariant.objects.filter(sku='HTMX-V1').exists()
|
|
|
|
def test_htmx_variant_delete_stays_and_refreshes(self):
|
|
size_m = self.create_attribute_value('Talla', 'M')
|
|
variant = self.create_product_variant(self.product, sku='HTMX-V2', attribute_values=[size_m])
|
|
|
|
response = self.client.post(
|
|
reverse('backoffice:product_variant_delete', args=[variant.pk]), HTTP_HX_REQUEST='true'
|
|
)
|
|
assert response.status_code == 204
|
|
assert 'HX-Redirect' not in response
|
|
trigger = json.loads(response['HX-Trigger'])
|
|
assert trigger['backoffice:list-changed'] is True
|
|
assert not ProductVariant.objects.filter(pk=variant.pk).exists()
|
|
|
|
def test_htmx_image_upload_triggers_refresh(self):
|
|
image = Image.new('RGB', (64, 64), '#ACACAC')
|
|
buffer = BytesIO()
|
|
image.save(fp=buffer, format='WEBP')
|
|
file = ContentFile(buffer.getvalue(), name='test.webp')
|
|
|
|
response = self.client.post(
|
|
reverse('backoffice:product_image_create', args=[self.product.pk]),
|
|
{'original': file},
|
|
format='multipart',
|
|
HTTP_HX_REQUEST='true',
|
|
)
|
|
assert response.status_code == 204
|
|
trigger = json.loads(response['HX-Trigger'])
|
|
assert trigger == {'backoffice:modal-close': True, 'backoffice:list-changed': True}
|
|
assert ProductImage.objects.filter(product=self.product).exists()
|
|
|
|
def test_htmx_product_delete_uses_hx_redirect_instead_of_trigger(self):
|
|
product = self.create_product(sku='HTMX-DEL')
|
|
|
|
response = self.client.post(reverse('backoffice:product_delete', args=[product.pk]), HTTP_HX_REQUEST='true')
|
|
assert response.status_code == 200
|
|
assert response['HX-Redirect'] == reverse('backoffice:product_list')
|
|
assert 'HX-Trigger' not in response
|
|
assert not Product.objects.filter(pk=product.pk).exists()
|
|
|
|
def test_htmx_list_self_refresh_returns_fragment(self):
|
|
response = self.client.get(reverse('backoffice:product_list'), HTTP_HX_REQUEST='true')
|
|
assert response.status_code == 200
|
|
body = response.content.decode()
|
|
assert '<html' not in body
|
|
assert 'id="backoffice-list"' in body
|
|
|
|
def test_htmx_product_detail_self_refresh_returns_fragment(self):
|
|
response = self.client.get(reverse('backoffice:product_detail', args=[self.product.pk]), HTTP_HX_REQUEST='true')
|
|
assert response.status_code == 200
|
|
body = response.content.decode()
|
|
assert '<html' not in body
|
|
assert 'id="backoffice-detail"' in body
|