"""Tests for FeishuChannel._split_elements_by_table_limit. Feishu cards reject messages that contain more than one table element (API error 11310: card table number over limit). The helper splits a flat list of card elements into groups so that each group contains at most one table, allowing nanobot to send multiple cards instead of failing. """ # Check optional Feishu dependencies before running tests try: from nanobot.channels import feishu FEISHU_AVAILABLE = getattr(feishu, "FEISHU_AVAILABLE", False) except ImportError: FEISHU_AVAILABLE = False if not FEISHU_AVAILABLE: import pytest pytest.skip("Feishu dependencies not installed (lark-oapi)", allow_module_level=True) from nanobot.channels.feishu import FeishuChannel def _md(text: str) -> dict: return {"tag": "markdown", "content": text} def _table() -> dict: return { "tag": "table", "columns": [{"tag": "column", "name": "c0", "display_name": "A", "width": "auto"}], "rows": [{"c0": "v"}], "page_size": 2, } split = FeishuChannel._split_elements_by_table_limit def test_empty_list_returns_single_empty_group() -> None: assert split([]) == [[]] def test_no_tables_returns_single_group() -> None: els = [_md("hello"), _md("world")] result = split(els) assert result == [els] def test_single_table_stays_in_one_group() -> None: els = [_md("intro"), _table(), _md("outro")] result = split(els) assert len(result) == 1 assert result[0] == els def test_two_tables_split_into_two_groups() -> None: # Use different row values so the two tables are not equal t1 = { "tag": "table", "columns": [{"tag": "column", "name": "c0", "display_name": "A", "width": "auto"}], "rows": [{"c0": "table-one"}], "page_size": 2, } t2 = { "tag": "table", "columns": [{"tag": "column", "name": "c0", "display_name": "B", "width": "auto"}], "rows": [{"c0": "table-two"}], "page_size": 2, } els = [_md("before"), t1, _md("between"), t2, _md("after")] result = split(els) assert len(result) == 2 # First group: text before table-1 + table-1 assert t1 in result[0] assert t2 not in result[0] # Second group: text between tables + table-2 + text after assert t2 in result[1] assert t1 not in result[1] def test_three_tables_split_into_three_groups() -> None: tables = [ {"tag": "table", "columns": [], "rows": [{"c0": f"t{i}"}], "page_size": 1} for i in range(3) ] els = tables[:] result = split(els) assert len(result) == 3 for i, group in enumerate(result): assert tables[i] in group def test_leading_markdown_stays_with_first_table() -> None: intro = _md("intro") t = _table() result = split([intro, t]) assert len(result) == 1 assert result[0] == [intro, t] def test_trailing_markdown_after_second_table() -> None: t1, t2 = _table(), _table() tail = _md("end") result = split([t1, t2, tail]) assert len(result) == 2 assert result[1] == [t2, tail] def test_non_table_elements_before_first_table_kept_in_first_group() -> None: head = _md("head") t1, t2 = _table(), _table() result = split([head, t1, t2]) # head + t1 in group 0; t2 in group 1 assert result[0] == [head, t1] assert result[1] == [t2]