Files
shoppy/backoffice/tests/test_htmx.py
T
pablo 2a9407e676
CI / ci (ubuntu-24.04, 3.13) (push) Has been cancelled
feat: backoffice setup
2026-07-23 13:31:53 +02:00

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