package com.yunhai.flowcenter.controller.api; import com.yunhai.platform.utils.model.BoaModule; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; /** * GetUserMod 映射单测:flow-center 已改为直接消费 UserBase 下发的模块树({@code BoaModule.children}), * 本侧只做前端 layout 契约的字段改名,不再本地组树。
* 另锁定两个易错点:modId 必须取 custom_id(对上 routes.ts 的 meta.modId 100~105), * 以及 children 恒为数组(叶子为空列表、上游未展开的 null 也要归零),否则前端递归会炸。 */ class FlowBaseControllerTest { @Test void toFrontendTree_shouldKeepServerHierarchyAndRenameFields() { BoaModule parent = module(501, "100", "/workbench", 1); BoaModule child = module(502, "101", "/my", 2); parent.setChildren(new ArrayList<>(Collections.singletonList(child))); BoaModule otherRoot = module(503, "105", "/admin/callbacks", 1); List> tree = FlowBaseController.toFrontendTree(Arrays.asList(parent, otherRoot)); assertEquals(2, tree.size(), "顶层只应有两个根,子节点不得浮到顶层"); Map first = tree.get(0); assertEquals("/workbench", first.get("page"), "path → page(前端按 page 匹配菜单高亮)"); assertEquals(100, first.get("modId"), "modId 必须取 custom_id 而非主键 id(routes.ts meta.modId 约定)"); assertEquals(501, first.get("id"), "原始主键仍经 id 字段透出"); @SuppressWarnings("unchecked") List> children = (List>) first.get("children"); assertEquals(1, children.size(), "层级应原样保留"); assertEquals(101, children.get(0).get("modId")); assertEquals("/my", children.get(0).get("page")); } @Test void toFrontendTree_shouldAlwaysEmitChildrenAsArray() { BoaModule configuredLeaf = module(601, "102", "/admin/instances", 1); configuredLeaf.setChildren(new ArrayList<>()); BoaModule notExpanded = module(602, "103", "/admin/defs", 1); // 上游未展开 → children 为 null List> tree = FlowBaseController.toFrontendTree(Arrays.asList(configuredLeaf, notExpanded)); for (Map node : tree) { assertNotNull(node.get("children"), "children 不得为 null,前端要无判空递归"); assertTrue(((List) node.get("children")).isEmpty(), "无子节点时应为空列表"); } } @Test void toFrontendTree_shouldFallBackToPrimaryKeyWhenCustomIdNotNumeric() { BoaModule m = module(701, "workbench-home", "/workbench", 1); List> tree = FlowBaseController.toFrontendTree(Collections.singletonList(m)); assertEquals(701, tree.get(0).get("modId"), "custom_id 非数字时回退模块主键 id"); } @Test void toFrontendTree_shouldTolerateNullPathAndEmptyInput() { BoaModule noPath = module(801, "104", null, 1); assertEquals("", FlowBaseController.toFrontendTree(Collections.singletonList(noPath)).get(0).get("page"), "path 缺失应给空串而非 null(前端字符串比较不判空)"); assertTrue(FlowBaseController.toFrontendTree(Collections.emptyList()).isEmpty()); assertTrue(FlowBaseController.toFrontendTree(null).isEmpty(), "上游返回 null 不得抛 NPE"); } private static BoaModule module(Integer id, String customId, String path, Integer level) { BoaModule m = new BoaModule(); m.setId(id); m.setCustomId(customId); m.setName("模块" + customId); m.setPath(path); m.setLevel(level); m.setSortNo(level * 10); return m; } }