Files
2026-moving-helper/tests/test_app.py
T

302 lines
8.7 KiB
Python
Raw Normal View History

2026-04-19 12:13:07 +02:00
from pathlib import Path
2026-04-19 12:36:55 +02:00
import app.db as db_module
from app.models import Box, Item, SubItem
2026-04-19 12:13:07 +02:00
2026-04-19 12:36:55 +02:00
def create_box(client, name="Box A", note="Packed", room="Bedroom", status="ready"):
return client.post(
"/boxes",
data={"name": name, "note": note, "room": room, "status": status},
follow_redirects=False,
)
def create_item(client, box_id, name="Item A", note="Note", quantity="2", is_container=False):
data = {"name": name, "note": note, "quantity": quantity}
if is_container:
data["is_container"] = "on"
return client.post(f"/boxes/{box_id}/items", data=data, follow_redirects=False)
def create_subitem(client, item_id, name="SubItem A", note="Small", quantity="3"):
return client.post(
f"/items/{item_id}/subitems",
data={"name": name, "note": note, "quantity": quantity},
follow_redirects=False,
)
2026-04-19 12:13:07 +02:00
2026-04-19 12:36:55 +02:00
def test_app_uses_isolated_sqlite_database(client):
assert db_module.engine is not None
database_name = Path(db_module.engine.url.database)
assert database_name.name == "test.db"
assert "data/app.db" not in str(database_name)
2026-04-19 12:13:07 +02:00
def test_root_redirects_to_boxes(client):
response = client.get("/", follow_redirects=False)
assert response.status_code == 302
assert response.headers["location"] == "/boxes"
def test_boxes_page_returns_200(client):
response = client.get("/boxes")
assert response.status_code == 200
2026-04-19 12:36:55 +02:00
assert "箱子" in response.text
2026-04-19 12:13:07 +02:00
2026-04-19 12:36:55 +02:00
def test_can_create_box(client, db_session):
response = create_box(client, name="Kitchen Box")
2026-04-19 12:13:07 +02:00
2026-04-19 12:36:55 +02:00
assert response.status_code == 303
box = db_session.query(Box).one()
assert box.name == "Kitchen Box"
assert box.room == "Bedroom"
def test_can_edit_box(client, db_session):
box = Box(name="Old Box")
db_session.add(box)
db_session.commit()
response = client.post(
f"/boxes/{box.id}/update",
data={"name": "Updated Box", "note": "Updated", "room": "Office", "status": "open"},
follow_redirects=False,
)
assert response.status_code == 303
db_session.refresh(box)
assert box.name == "Updated Box"
assert box.room == "Office"
assert box.status == "open"
def test_can_delete_box(client, db_session):
box = Box(name="Delete Me")
db_session.add(box)
db_session.commit()
box_id = box.id
response = client.post(f"/boxes/{box_id}/delete", follow_redirects=False)
assert response.status_code == 303
db_session.expire_all()
assert db_session.get(Box, box_id) is None
def test_deleting_box_cascades_to_items_and_subitems(client, db_session):
box = Box(name="Cascade Box")
item = Item(name="Container", is_container=True, box=box)
subitem = SubItem(name="Cable", parent_item=item)
db_session.add_all([box, item, subitem])
db_session.commit()
response = client.post(f"/boxes/{box.id}/delete", follow_redirects=False)
assert response.status_code == 303
assert db_session.query(Box).count() == 0
assert db_session.query(Item).count() == 0
assert db_session.query(SubItem).count() == 0
def test_missing_box_returns_404(client):
response = client.get("/boxes/9999")
assert response.status_code == 404
def test_box_detail_returns_200_when_box_exists(client, db_session):
box = Box(name="Visible Box")
db_session.add(box)
db_session.commit()
response = client.get(f"/boxes/{box.id}")
assert response.status_code == 200
assert "Visible Box" in response.text
def test_can_create_regular_item_under_box(client, db_session):
box = Box(name="Main Box")
db_session.add(box)
db_session.commit()
response = create_item(client, box.id, name="Book", is_container=False)
assert response.status_code == 303
item = db_session.query(Item).one()
assert item.name == "Book"
assert item.is_container is False
def test_can_create_container_item_under_box(client, db_session):
box = Box(name="Main Box")
db_session.add(box)
db_session.commit()
response = create_item(client, box.id, name="Accessory Pouch", is_container=True)
assert response.status_code == 303
item = db_session.query(Item).one()
assert item.is_container is True
def test_can_edit_item(client, db_session):
box = Box(name="Main Box")
item = Item(name="Old Item", box=box, is_container=False)
db_session.add_all([box, item])
db_session.commit()
response = client.post(
f"/items/{item.id}/update",
data={"name": "New Item", "note": "Changed", "quantity": "7", "is_container": "on"},
follow_redirects=False,
)
assert response.status_code == 303
db_session.refresh(item)
assert item.name == "New Item"
assert item.quantity == 7
assert item.is_container is True
def test_can_delete_item(client, db_session):
box = Box(name="Main Box")
item = Item(name="Delete Item", box=box, is_container=False)
db_session.add_all([box, item])
db_session.commit()
item_id = item.id
response = client.post(f"/items/{item_id}/delete", follow_redirects=False)
assert response.status_code == 303
db_session.expire_all()
assert db_session.get(Item, item_id) is None
def test_deleting_container_item_cascades_to_subitems(client, db_session):
box = Box(name="Main Box")
item = Item(name="Container", box=box, is_container=True)
subitem = SubItem(name="Clip", parent_item=item)
db_session.add_all([box, item, subitem])
db_session.commit()
response = client.post(f"/items/{item.id}/delete", follow_redirects=False)
assert response.status_code == 303
assert db_session.query(Item).count() == 0
assert db_session.query(SubItem).count() == 0
def test_missing_item_returns_404(client):
response = client.get("/items/9999")
assert response.status_code == 404
def test_item_detail_returns_200_when_item_exists(client, db_session):
box = Box(name="Main Box")
item = Item(name="Visible Item", box=box, is_container=False)
db_session.add_all([box, item])
db_session.commit()
response = client.get(f"/items/{item.id}")
assert response.status_code == 200
assert "Visible Item" in response.text
def test_can_create_subitem_under_container_item(client, db_session):
box = Box(name="Main Box")
item = Item(name="Pouch", box=box, is_container=True)
db_session.add_all([box, item])
db_session.commit()
response = create_subitem(client, item.id, name="USB Cable")
assert response.status_code == 303
subitem = db_session.query(SubItem).one()
assert subitem.name == "USB Cable"
def test_cannot_create_subitem_under_non_container_item(client, db_session):
box = Box(name="Main Box")
item = Item(name="Book", box=box, is_container=False)
db_session.add_all([box, item])
db_session.commit()
response = create_subitem(client, item.id, name="Should Fail")
assert response.status_code == 400
assert response.json()["detail"] == "Only container items can have sub-items"
assert db_session.query(SubItem).count() == 0
def test_can_edit_subitem(client, db_session):
box = Box(name="Main Box")
item = Item(name="Pouch", box=box, is_container=True)
subitem = SubItem(name="Old Sub-item", parent_item=item)
db_session.add_all([box, item, subitem])
db_session.commit()
response = client.post(
f"/subitems/{subitem.id}/update",
data={"name": "New Sub-item", "note": "Updated", "quantity": "9"},
follow_redirects=False,
)
assert response.status_code == 303
db_session.refresh(subitem)
assert subitem.name == "New Sub-item"
assert subitem.quantity == 9
def test_can_delete_subitem(client, db_session):
box = Box(name="Main Box")
item = Item(name="Pouch", box=box, is_container=True)
subitem = SubItem(name="Delete Sub-item", parent_item=item)
db_session.add_all([box, item, subitem])
db_session.commit()
subitem_id = subitem.id
response = client.post(f"/subitems/{subitem_id}/delete", follow_redirects=False)
assert response.status_code == 303
db_session.expire_all()
assert db_session.get(SubItem, subitem_id) is None
def test_missing_subitem_returns_404(client):
response = client.get("/subitems/9999/edit")
assert response.status_code == 404
def test_post_redirects_are_reasonable(client, db_session):
box = Box(name="Redirect Box")
db_session.add(box)
db_session.commit()
item_response = create_item(client, box.id, name="Lamp")
item_id = int(item_response.headers["location"].split("/")[-1])
item = db_session.get(Item, item_id)
item.is_container = True
db_session.commit()
subitem_response = create_subitem(client, item.id, name="Bulb")
assert item_response.headers["location"] == f"/items/{item.id}"
assert subitem_response.headers["location"] == f"/items/{item.id}"