test: explicit tag delete-cascade cleanup test (MPS-24)
Operator-facing concern: 'can I experiment with auto-suggested tags and undo cleanly without DB cruft?' Yes — Phase 1 already wires the SQLAlchemy cascade via ProductTag.tag's backref (cascade='all, delete-orphan'), but the existing functional test only verified the Tag row went away. This adds an end-to-end test that: 1. Applies a tag to 3 products via action=apply_suggestion (creating 3 ProductTag rows). 2. Deletes the tag via action=delete. 3. Asserts: Tag row gone, all 3 ProductTag rows gone, products survive with empty .tags. Proves reversibility for an operator testing categorizations on the suggest-then-approve loop.
This commit is contained in:
parent
8b25285647
commit
28ffee6c8c
1 changed files with 60 additions and 0 deletions
|
|
@ -8618,3 +8618,63 @@ class TestHomeLayoutAndTags(_AuthenticatedBase):
|
|||
if res.status_int == 302:
|
||||
res = res.follow()
|
||||
self.assertIn("Could not apply suggestion", res.body.decode())
|
||||
|
||||
def test_tag_delete_cascade_cleans_product_associations(self):
|
||||
"""Deleting a tag cascade-deletes every ProductTag row pointing
|
||||
at it. The operator can apply experimental tags, dislike them,
|
||||
and delete them — no orphan rows accumulate in the DB."""
|
||||
shop, products = self._make_shop_with_products(
|
||||
"cascade-shop",
|
||||
[
|
||||
("Alpha Product", "Body one."),
|
||||
("Beta Product", "Body two."),
|
||||
("Gamma Product", "Body three."),
|
||||
],
|
||||
)
|
||||
product_ids = [str(p.id) for p in products]
|
||||
|
||||
# Apply a tag to all three via the suggest-apply path
|
||||
self.testapp.post(
|
||||
f"/s/{shop.id}/tags",
|
||||
{
|
||||
"action": "apply_suggestion",
|
||||
"label": "Experimental",
|
||||
"product_ids": ",".join(product_ids),
|
||||
},
|
||||
)
|
||||
from ..models.tag import get_tag_by_shop_and_slug
|
||||
from ..models.product_tag import ProductTag
|
||||
self.dbsession.expire_all()
|
||||
tag = get_tag_by_shop_and_slug(self.dbsession, shop, "experimental")
|
||||
self.assertIsNotNone(tag)
|
||||
tag_id = tag.id
|
||||
self.assertEqual(
|
||||
self.dbsession.query(ProductTag)
|
||||
.filter(ProductTag.tag_id == tag_id)
|
||||
.count(),
|
||||
3,
|
||||
)
|
||||
|
||||
# Delete the tag — cascade must clean all ProductTag rows
|
||||
self.testapp.post(
|
||||
f"/s/{shop.id}/tags",
|
||||
{"action": "delete", "tag_slug": "experimental"},
|
||||
)
|
||||
self.dbsession.expire_all()
|
||||
# Tag itself gone
|
||||
self.assertIsNone(
|
||||
get_tag_by_shop_and_slug(self.dbsession, shop, "experimental")
|
||||
)
|
||||
# Zero orphan ProductTag rows for the deleted tag
|
||||
self.assertEqual(
|
||||
self.dbsession.query(ProductTag)
|
||||
.filter(ProductTag.tag_id == tag_id)
|
||||
.count(),
|
||||
0,
|
||||
)
|
||||
# Products themselves survive + carry no tags
|
||||
from ..models.product import get_product_by_id
|
||||
for pid in product_ids:
|
||||
p = get_product_by_id(self.dbsession, pid)
|
||||
self.assertIsNotNone(p)
|
||||
self.assertEqual(list(p.tags), [])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue