106 lines
4.7 KiB
Python
106 lines
4.7 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_product_create_is_a_full_page_not_a_modal_fragment(self):
|
|
# ProductCreateView ya no es modal: navegar a la URL de creación siempre
|
|
# devuelve la página completa, incluso si la petición lleva HX-Request.
|
|
response = self.client.get(reverse('backoffice:product_create'), HTTP_HX_REQUEST='true')
|
|
assert response.status_code == 200
|
|
body = response.content.decode()
|
|
assert '<html' in body
|
|
assert 'Nuevo producto' in body
|
|
|
|
def test_product_create_redirects_to_detail_even_with_hx_request(self):
|
|
response = self.client.post(
|
|
reverse('backoffice:product_create'),
|
|
{'sku': 'HTMX-1', 'name': 'Producto htmx', 'description': '', 'stock': '0'},
|
|
HTTP_HX_REQUEST='true',
|
|
)
|
|
product = Product.objects.get(sku='HTMX-1')
|
|
assert response.status_code == 302
|
|
assert response.url == reverse('backoffice:product_detail', args=[product.pk])
|
|
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
|