Files

144 lines
4.1 KiB
Python
Raw Permalink Normal View History

2026-04-19 14:28:00 +02:00
from app.models import Box, Item, SubItem
from app.notion_import import (
ImportSummary,
ParsedBox,
ParsedItem,
ParsedSubItem,
apply_import,
extract_page_id,
parse_notion_blocks,
)
def make_heading_2(text: str) -> dict:
return {
"type": "heading_2",
"heading_2": {"rich_text": [{"plain_text": text}]},
"_children": [],
}
def make_bullet(text: str, children: list[dict] | None = None) -> dict:
return {
"type": "bulleted_list_item",
"bulleted_list_item": {"rich_text": [{"plain_text": text}]},
"_children": children or [],
}
def make_image_block() -> dict:
return {"type": "image", "image": {}, "_children": []}
def test_extract_page_id_from_notion_url():
url = "https://www.notion.so/workspace/My-Page-1234567890abcdef1234567890abcdef?pvs=4"
page_id = extract_page_id(url)
assert page_id == "12345678-90ab-cdef-1234-567890abcdef"
def test_parse_heading_2_as_box():
summary = parse_notion_blocks([make_heading_2("厨房箱")])
assert summary.box_count == 1
assert summary.boxes[0].name == "厨房箱"
def test_parse_first_level_bullet_as_item():
blocks = [make_heading_2("客厅箱"), make_bullet("锅具")]
summary = parse_notion_blocks(blocks)
assert summary.item_count == 1
assert summary.boxes[0].items[0].name == "锅具"
assert summary.boxes[0].items[0].is_container is False
def test_parse_bullet_with_children_as_container_item_and_subitems():
blocks = [
make_heading_2("电子箱"),
make_bullet("配件盒", children=[make_bullet("USB 线"), make_bullet("转接头")]),
]
summary = parse_notion_blocks(blocks)
item = summary.boxes[0].items[0]
assert item.name == "配件盒"
assert item.is_container is True
assert [subitem.name for subitem in item.subitems] == ["USB 线", "转接头"]
def test_parse_second_level_bullets_as_subitems():
blocks = [
make_heading_2("文件箱"),
make_bullet("文件袋", children=[make_bullet("合同"), make_bullet("护照复印件")]),
]
summary = parse_notion_blocks(blocks)
assert summary.subitem_count == 2
assert summary.boxes[0].items[0].subitems[1].name == "护照复印件"
def test_parse_deeper_than_supported_levels_adds_warning():
blocks = [
make_heading_2("测试箱"),
make_bullet(
"外层袋",
children=[make_bullet("内层物品", children=[make_bullet("更深一层")])],
),
]
summary = parse_notion_blocks(blocks)
assert summary.container_item_count == 1
assert any("超出支持层级" in warning for warning in summary.warnings)
def test_parse_non_text_media_block_adds_skip_warning():
blocks = [make_heading_2("照片箱"), make_image_block()]
summary = parse_notion_blocks(blocks)
assert any("这版不导入图片或媒体" in warning for warning in summary.warnings)
def test_dry_run_parse_does_not_write_database(db_session):
blocks = [make_heading_2("厨房箱"), make_bullet("")]
summary = parse_notion_blocks(blocks)
assert summary.box_count == 1
assert db_session.query(Box).count() == 0
assert db_session.query(Item).count() == 0
assert db_session.query(SubItem).count() == 0
def test_apply_import_writes_expected_structure(db_session):
summary = ImportSummary(
boxes=[
ParsedBox(
name="主卧箱",
items=[
ParsedItem(name="衣服", is_container=False),
ParsedItem(
name="收纳袋",
is_container=True,
subitems=[ParsedSubItem(name="袜子"), ParsedSubItem(name="围巾")],
),
],
)
]
)
counts = apply_import(summary, db_session)
assert counts == {"boxes": 1, "items": 2, "subitems": 2}
assert db_session.query(Box).count() == 1
assert db_session.query(Item).count() == 2
assert db_session.query(SubItem).count() == 2
container_item = db_session.query(Item).filter_by(name="收纳袋").one()
assert container_item.is_container is True