"""Fixture payloads for ``POST /usercenter/dept/tree`` (Task 2.0). yunke's dept/tree endpoint follows the same convention as the permissions API: nodes carry ``id`` / ``pId`` / ``name``, and the tree MAY be delivered either as a flat list of nodes or as a nested tree (each node optionally carrying a ``children`` array). The scraper must flatten both shapes into one flat list of nodes and reconstruct ``parent_id`` from ``pId``. This cassette provides TWO realistic capture-shaped payloads so the scraper tests can prove both shapes flatten to the SAME set of nodes: * ``NESTED_TREE_PAYLOAD`` — a root with two children, one of which has its own sub-child (3 levels deep). Nested via ``children``. * ``FLAT_TREE_PAYLOAD`` — the exact same 4 nodes delivered as a flat list (parent links carried by ``pId``). Both decode to the same 4 departments with the same ids / parents / names / paths, so the scraper test can swap the envelope and re-assert. The 4 nodes: root "Sales" (id="1", pId="0") ├── "East" (id="1.1", pId="1") │ └── "TeamA" (id="1.1.1", pId="1.1") └── "North" (id="1.2", pId="1") """ from __future__ import annotations from typing import Any # --------------------------------------------------------------------------- # The canonical 4 nodes (single source of truth for both shapes below) # --------------------------------------------------------------------------- # Root has pId="0" — the common yunke convention for "no parent". The scraper # treats any falsy pId (None / "" / "0") OR an unknown pId as "root". ROOT_NODE: dict[str, Any] = {"id": "1", "pId": "0", "name": "Sales"} EAST_NODE: dict[str, Any] = {"id": "1.1", "pId": "1", "name": "East"} TEAMA_NODE: dict[str, Any] = {"id": "1.1.1", "pId": "1.1", "name": "TeamA"} NORTH_NODE: dict[str, Any] = {"id": "1.2", "pId": "1", "name": "North"} # All four nodes, in a stable order matching a depth-first traversal of the # nested tree. Tests assert the scraper yields exactly these (order is not # load-bearing — tests compare as sets where appropriate). ALL_NODES: list[dict[str, Any]] = [ROOT_NODE, EAST_NODE, TEAMA_NODE, NORTH_NODE] # --------------------------------------------------------------------------- # Nested envelope — root carries children, recursively # --------------------------------------------------------------------------- NESTED_TREE_NODES: list[dict[str, Any]] = [ { **ROOT_NODE, "children": [ { **EAST_NODE, "children": [{**TEAMA_NODE}], }, {**NORTH_NODE}, ], }, ] # --------------------------------------------------------------------------- # Flat envelope — every node at the top level, parents via pId # --------------------------------------------------------------------------- FLAT_TREE_NODES: list[dict[str, Any]] = [ {**ROOT_NODE}, {**EAST_NODE}, {**TEAMA_NODE}, {**NORTH_NODE}, ] def make_dept_tree_response( nodes: list[dict[str, Any]], *, nested_in_data_object: bool = False, trace_id: str = "trace-dept", ) -> dict[str, Any]: """Build a capture-shaped ``dept/tree`` response envelope. The yunke dept/tree response top-level is the standard envelope ``{message, code:"10000", success, traceId, data}``. The shape of ``data`` itself varies between captures — be defensive: * ``data`` is the node list directly (the common case), OR * ``data`` is an object wrapping the node list under ``children`` / ``list`` / etc. The ``nested_in_data_object`` flag selects the second variant for the "wrapped data object" path so a test can prove the scraper unwraps it. The default (``False``) emits the most common flat-data array shape. """ data: Any = list(nodes) if nested_in_data_object: data = {"children": list(nodes)} return { "message": "调用成功", "code": "10000", "success": True, "traceId": trace_id, "data": data, }