This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new 2871f3bf fix: scope topic diagnostics to selected instance (#1128)
2871f3bf is described below

commit 2871f3bfc29c76e8078aae84e1b2543f690140fe
Author: aias00 <[email protected]>
AuthorDate: Thu Aug 6 23:56:34 2026 -0700

    fix: scope topic diagnostics to selected instance (#1128)
---
 .../studio/instance/topic/MetadataService.java     |   2 +-
 .../provider/apache/ApacheInstanceProvider.java    |   2 +-
 .../studio/provider/apache/MetadataProvider.java   |   4 +-
 .../provider/apache/RocketMQMetadataProvider.java  | 193 +++++++++++----------
 .../studio/instance/topic/MetadataServiceTest.java |  14 ++
 .../studio/instance/topic/TopicControllerTest.java |  16 ++
 .../apache/RocketMQMetadataProviderTest.java       |  30 +++-
 web/src/api/metadata.test.ts                       |  12 +-
 .../pages/instance/__tests__/TopicPage.test.tsx    |  20 ++-
 9 files changed, 191 insertions(+), 102 deletions(-)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataService.java
 
b/server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataService.java
index 04b80abe..fa7b1eae 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataService.java
@@ -88,7 +88,7 @@ public class MetadataService {
             // broker routing does not apply to serverless cloud instances
             return List.of();
         }
-        return metadataProvider.getTopicRoutes(name);
+        return metadataProvider.getTopicRoutes(instanceId, name);
     }
 
 
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/ApacheInstanceProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/ApacheInstanceProvider.java
index a9e4236a..4915303a 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/ApacheInstanceProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/ApacheInstanceProvider.java
@@ -85,7 +85,7 @@ public class ApacheInstanceProvider implements 
InstanceProvider {
 
     @Override
     public List<TopicConsumerVO> getTopicConsumers(String instanceId, String 
topicName) {
-        return metadataProvider.getTopicConsumers(topicName);
+        return metadataProvider.getTopicConsumers(instanceId, topicName);
     }
 
     @Override
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/MetadataProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/MetadataProvider.java
index e5ccef5c..173e7c8a 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/MetadataProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/MetadataProvider.java
@@ -28,8 +28,8 @@ import java.util.List;
 public interface MetadataProvider {
     List<TopicVO> listTopics(String clusterId, String type, String search);
     List<ConsumerGroupVO> listConsumerGroups(String clusterId, String search);
-    List<BrokerRouteVO> getTopicRoutes(String name);
-    List<TopicConsumerVO> getTopicConsumers(String name);
+    List<BrokerRouteVO> getTopicRoutes(String instanceId, String name);
+    List<TopicConsumerVO> getTopicConsumers(String instanceId, String name);
     List<QueueProgressVO> getGroupProgress(String name);
     List<SubscriptionEntryVO> getGroupSubscriptions(String name);
 }
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProvider.java
index 90233979..b17703bb 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProvider.java
@@ -28,6 +28,8 @@ import org.apache.rocketmq.remoting.protocol.route.BrokerData;
 import org.apache.rocketmq.remoting.protocol.route.QueueData;
 import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
 import org.apache.rocketmq.studio.cluster.broker.MqAdminExtFactory;
+import org.apache.rocketmq.studio.cluster.broker.RuntimeAdminClientResolver;
+import org.apache.rocketmq.tools.admin.MQAdminExt;
 import org.apache.rocketmq.studio.common.domain.enums.ConsumeType;
 import org.apache.rocketmq.studio.common.domain.enums.TopicPerm;
 import org.apache.rocketmq.studio.common.domain.enums.TopicType;
@@ -83,6 +85,7 @@ public class RocketMQMetadataProvider implements 
MetadataProvider {
     private final RocketMQProperties properties;
     private final RmqTopicMapper topicMapper;
     private final RmqGroupMapper groupMapper;
+    private final RuntimeAdminClientResolver runtimeAdminClientResolver;
 
     /** Whether a default NameServer is configured and live queries are 
therefore possible. */
     private boolean hasAdmin() {
@@ -192,125 +195,133 @@ public class RocketMQMetadataProvider implements 
MetadataProvider {
     }
 
     @Override
-    public List<BrokerRouteVO> getTopicRoutes(String name) {
+    public List<BrokerRouteVO> getTopicRoutes(String instanceId, String name) {
+        if (StringUtils.hasText(instanceId)) {
+            return runtimeAdminClientResolver.execute(instanceId, admin -> 
getTopicRoutes(admin, name));
+        }
         if (!hasAdmin()) {
             return Collections.emptyList();
         }
+        return adminExecute(admin -> getTopicRoutes(admin, name));
+    }
 
-        return adminExecute(admin -> {
-            try {
-                TopicRouteData routeData = admin.examineTopicRouteInfo(name);
-                if (routeData == null) {
-                    return Collections.emptyList();
-                }
+    private List<BrokerRouteVO> getTopicRoutes(MQAdminExt admin, String name) {
+        try {
+            TopicRouteData routeData = admin.examineTopicRouteInfo(name);
+            if (routeData == null) {
+                return Collections.emptyList();
+            }
 
-                Map<String, BrokerData> brokerDataMap = new HashMap<>();
-                if (routeData.getBrokerDatas() != null) {
-                    for (BrokerData bd : routeData.getBrokerDatas()) {
-                        brokerDataMap.put(bd.getBrokerName(), bd);
-                    }
+            Map<String, BrokerData> brokerDataMap = new HashMap<>();
+            if (routeData.getBrokerDatas() != null) {
+                for (BrokerData bd : routeData.getBrokerDatas()) {
+                    brokerDataMap.put(bd.getBrokerName(), bd);
                 }
+            }
 
-                List<BrokerRouteVO> routes = new ArrayList<>();
-                if (routeData.getQueueDatas() != null) {
-                    for (QueueData qd : routeData.getQueueDatas()) {
-                        BrokerData bd = brokerDataMap.get(qd.getBrokerName());
-                        String brokerAddr = "";
-                        if (bd != null && bd.getBrokerAddrs() != null && 
!bd.getBrokerAddrs().isEmpty()) {
-                            brokerAddr = 
bd.getBrokerAddrs().get(MixAll.MASTER_ID);
-                            if (brokerAddr == null) {
-                                brokerAddr = 
bd.getBrokerAddrs().values().iterator().next();
-                            }
+            List<BrokerRouteVO> routes = new ArrayList<>();
+            if (routeData.getQueueDatas() != null) {
+                for (QueueData qd : routeData.getQueueDatas()) {
+                    BrokerData bd = brokerDataMap.get(qd.getBrokerName());
+                    String brokerAddr = "";
+                    if (bd != null && bd.getBrokerAddrs() != null && 
!bd.getBrokerAddrs().isEmpty()) {
+                        brokerAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
+                        if (brokerAddr == null) {
+                            brokerAddr = 
bd.getBrokerAddrs().values().iterator().next();
                         }
-
-                        routes.add(BrokerRouteVO.builder()
-                                .brokerName(qd.getBrokerName())
-                                .brokerAddr(brokerAddr)
-                                .writeQueues(qd.getWriteQueueNums())
-                                .readQueues(qd.getReadQueueNums())
-                                .perm(mapPerm(qd.getPerm()))
-                                .build());
                     }
+
+                    routes.add(BrokerRouteVO.builder()
+                            .brokerName(qd.getBrokerName())
+                            .brokerAddr(brokerAddr)
+                            .writeQueues(qd.getWriteQueueNums())
+                            .readQueues(qd.getReadQueueNums())
+                            .perm(mapPerm(qd.getPerm()))
+                            .build());
                 }
-                return routes;
-            } catch (Exception e) {
-                log.warn("Failed to get routes for topic {}: {}", name, 
e.getMessage());
-                return Collections.emptyList();
             }
-        });
+            return routes;
+        } catch (Exception e) {
+            log.warn("Failed to get routes for topic {}: {}", name, 
e.getMessage());
+            return Collections.emptyList();
+        }
     }
 
     @Override
-    public List<TopicConsumerVO> getTopicConsumers(String name) {
+    public List<TopicConsumerVO> getTopicConsumers(String instanceId, String 
name) {
+        if (StringUtils.hasText(instanceId)) {
+            return runtimeAdminClientResolver.execute(instanceId, admin -> 
getTopicConsumers(admin, name));
+        }
         if (!hasAdmin()) {
             return Collections.emptyList();
         }
+        return adminExecute(admin -> getTopicConsumers(admin, name));
+    }
 
-        return adminExecute(admin -> {
-            try {
-                // Ask the broker who consumes this topic instead of scanning 
every subscription
-                // group, which floods the result with system groups.
-                GroupList groupList = admin.queryTopicConsumeByWho(name);
-                Set<String> subscribingGroups = new HashSet<>();
-                if (groupList != null && groupList.getGroupList() != null) {
-                    for (String group : groupList.getGroupList()) {
-                        if (!isSystemConsumerGroup(group)) {
-                            subscribingGroups.add(group);
-                        }
+    private List<TopicConsumerVO> getTopicConsumers(MQAdminExt admin, String 
name) {
+        try {
+            // Ask the broker who consumes this topic instead of scanning 
every subscription
+            // group, which floods the result with system groups.
+            GroupList groupList = admin.queryTopicConsumeByWho(name);
+            Set<String> subscribingGroups = new HashSet<>();
+            if (groupList != null && groupList.getGroupList() != null) {
+                for (String group : groupList.getGroupList()) {
+                    if (!isSystemConsumerGroup(group)) {
+                        subscribingGroups.add(group);
                     }
                 }
+            }
 
-                List<TopicConsumerVO> consumers = new ArrayList<>();
-                for (String group : subscribingGroups) {
-                    try {
-                        ConsumeStats stats = admin.examineConsumeStats(group, 
name);
-                        long diffTotal = 0;
-                        double consumeTps = 0;
-                        if (stats != null && stats.getOffsetTable() != null) {
-                            for (Map.Entry<MessageQueue, OffsetWrapper> entry 
: stats.getOffsetTable().entrySet()) {
-                                OffsetWrapper ow = entry.getValue();
-                                diffTotal += Math.max(0, ow.getBrokerOffset() 
- ow.getConsumerOffset());
-                            }
-                            consumeTps = stats.getConsumeTps();
+            List<TopicConsumerVO> consumers = new ArrayList<>();
+            for (String group : subscribingGroups) {
+                try {
+                    ConsumeStats stats = admin.examineConsumeStats(group, 
name);
+                    long diffTotal = 0;
+                    double consumeTps = 0;
+                    if (stats != null && stats.getOffsetTable() != null) {
+                        for (Map.Entry<MessageQueue, OffsetWrapper> entry : 
stats.getOffsetTable().entrySet()) {
+                            OffsetWrapper ow = entry.getValue();
+                            diffTotal += Math.max(0, ow.getBrokerOffset() - 
ow.getConsumerOffset());
                         }
+                        consumeTps = stats.getConsumeTps();
+                    }
 
-                        ConsumeType consumeType = ConsumeType.CLUSTERING;
-                        String messageModel = "CLUSTERING";
-                        try {
-                            ConsumerConnection conn = 
admin.examineConsumerConnectionInfo(group);
-                            if (conn != null && conn.getMessageModel() != 
null) {
-                                messageModel = conn.getMessageModel().name();
-                                consumeType = parseConsumeType(messageModel);
-                            }
-                        } catch (Exception ignored) {
-                            // group may be offline
+                    ConsumeType consumeType = ConsumeType.CLUSTERING;
+                    String messageModel = "CLUSTERING";
+                    try {
+                        ConsumerConnection conn = 
admin.examineConsumerConnectionInfo(group);
+                        if (conn != null && conn.getMessageModel() != null) {
+                            messageModel = conn.getMessageModel().name();
+                            consumeType = parseConsumeType(messageModel);
                         }
-
-                        consumers.add(TopicConsumerVO.builder()
-                                .group(group)
-                                .consumeType(consumeType)
-                                .messageModel(messageModel)
-                                .consumeTps(consumeTps)
-                                .diffTotal(diffTotal)
-                                .build());
                     } catch (Exception ignored) {
-                        // stats unavailable for this group, still list it 
below without numbers
-                        consumers.add(TopicConsumerVO.builder()
-                                .group(group)
-                                .consumeType(ConsumeType.CLUSTERING)
-                                .messageModel("CLUSTERING")
-                                .consumeTps(0)
-                                .diffTotal(0)
-                                .build());
+                        // group may be offline
                     }
+
+                    consumers.add(TopicConsumerVO.builder()
+                            .group(group)
+                            .consumeType(consumeType)
+                            .messageModel(messageModel)
+                            .consumeTps(consumeTps)
+                            .diffTotal(diffTotal)
+                            .build());
+                } catch (Exception ignored) {
+                    // stats unavailable for this group, still list it below 
without numbers
+                    consumers.add(TopicConsumerVO.builder()
+                            .group(group)
+                            .consumeType(ConsumeType.CLUSTERING)
+                            .messageModel("CLUSTERING")
+                            .consumeTps(0)
+                            .diffTotal(0)
+                            .build());
                 }
-                consumers.sort((a, b) -> 
a.getGroup().compareToIgnoreCase(b.getGroup()));
-                return consumers;
-            } catch (Exception e) {
-                log.warn("Failed to get consumers for topic {}: {}", name, 
e.getMessage());
-                return Collections.emptyList();
             }
-        });
+            consumers.sort((a, b) -> 
a.getGroup().compareToIgnoreCase(b.getGroup()));
+            return consumers;
+        } catch (Exception e) {
+            log.warn("Failed to get consumers for topic {}: {}", name, 
e.getMessage());
+            return Collections.emptyList();
+        }
     }
 
     private boolean isSystemConsumerGroup(String group) {
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/instance/topic/MetadataServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/instance/topic/MetadataServiceTest.java
index caa06436..4d6d02e1 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/instance/topic/MetadataServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/instance/topic/MetadataServiceTest.java
@@ -157,6 +157,20 @@ class MetadataServiceTest {
         verify(apacheProvider).deleteTopic(null, "topic-to-delete");
     }
 
+    @Test
+    void topicRuntimeDiagnosticsShouldDelegateWithSelectedInstance() {
+        BrokerRouteVO route = 
BrokerRouteVO.builder().brokerName("broker-a").build();
+        TopicConsumerVO consumer = 
TopicConsumerVO.builder().group("cg-orders").build();
+        when(metadataProvider.getTopicRoutes("instance-a", 
"orders")).thenReturn(List.of(route));
+        when(apacheProvider.getTopicConsumers("instance-a", 
"orders")).thenReturn(List.of(consumer));
+
+        assertThat(metadataService.getTopicRoutes("instance-a", 
"orders")).containsExactly(route);
+        assertThat(metadataService.getTopicConsumers("instance-a", 
"orders")).containsExactly(consumer);
+
+        verify(metadataProvider).getTopicRoutes("instance-a", "orders");
+        verify(apacheProvider).getTopicConsumers("instance-a", "orders");
+    }
+
     @Test
     void sendMessageShouldReturnResult() {
         SendMessageDTO request = SendMessageDTO.builder()
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/instance/topic/TopicControllerTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/instance/topic/TopicControllerTest.java
index 6da4af95..4cdd8317 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/instance/topic/TopicControllerTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/instance/topic/TopicControllerTest.java
@@ -87,6 +87,22 @@ class TopicControllerTest {
         verify(metadataService).listTopics(isNull(), eq("cluster-1"), 
eq("NORMAL"), eq("test"));
     }
 
+    @Test
+    void topicRuntimeDiagnosticsShouldPassSelectedInstance() throws Exception {
+        when(metadataService.getTopicRoutes("instance-a", 
"orders")).thenReturn(List.of());
+        when(metadataService.getTopicConsumers("instance-a", 
"orders")).thenReturn(List.of());
+
+        mockMvc.perform(get("/api/topics/orders/routes").param("instanceId", 
"instance-a"))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200));
+        
mockMvc.perform(get("/api/topics/orders/consumers").param("instanceId", 
"instance-a"))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200));
+
+        verify(metadataService).getTopicRoutes("instance-a", "orders");
+        verify(metadataService).getTopicConsumers("instance-a", "orders");
+    }
+
     @Test
     void createTopicShouldReturnCreatedTopic() throws Exception {
         TopicVO input = new TopicVO();
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProviderTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProviderTest.java
index e7cf16a1..55991581 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProviderTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProviderTest.java
@@ -18,6 +18,9 @@ package org.apache.rocketmq.studio.provider.apache;
 
 import org.apache.rocketmq.studio.cluster.broker.MqAdminExtFactory;
 import org.apache.rocketmq.studio.common.domain.enums.ConsumeType;
+import org.apache.rocketmq.studio.cluster.broker.RuntimeAdminClientResolver;
+import org.apache.rocketmq.studio.instance.topic.BrokerRouteVO;
+import org.apache.rocketmq.studio.instance.topic.TopicConsumerVO;
 import org.apache.rocketmq.studio.instance.group.ConsumerGroupVO;
 import org.apache.rocketmq.studio.persistence.entity.RmqGroup;
 import org.apache.rocketmq.studio.persistence.mapper.RmqGroupMapper;
@@ -31,7 +34,9 @@ import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(MockitoExtension.class)
@@ -43,13 +48,16 @@ class RocketMQMetadataProviderTest {
     @Mock
     private RmqGroupMapper groupMapper;
 
+    @Mock
+    private RuntimeAdminClientResolver runtimeAdminClientResolver;
+
     /**
      * Builds a provider without a configured NameServer, mirroring the former 
absent admin bean:
      * DB-backed listings work while live enrichment is skipped.
      */
     private RocketMQMetadataProvider newProvider() {
         return new RocketMQMetadataProvider(mock(MqAdminExtFactory.class), new 
RocketMQProperties(),
-                topicMapper, groupMapper);
+                topicMapper, groupMapper, runtimeAdminClientResolver);
     }
 
     @Test
@@ -85,4 +93,24 @@ class RocketMQMetadataProviderTest {
         assertThat(groups).hasSize(1);
         
assertThat(groups.get(0).getConsumeType()).isEqualTo(ConsumeType.CLUSTERING);
     }
+
+    @Test
+    void getTopicRoutesShouldUseSelectedInstanceRuntimeClient() {
+        List<BrokerRouteVO> routes = 
List.of(BrokerRouteVO.builder().brokerName("broker-a").build());
+        when(runtimeAdminClientResolver.execute(eq("instance-a"), 
any())).thenReturn(routes);
+        RocketMQMetadataProvider provider = newProvider();
+
+        assertThat(provider.getTopicRoutes("instance-a", 
"orders")).containsExactlyElementsOf(routes);
+        verify(runtimeAdminClientResolver).execute(eq("instance-a"), any());
+    }
+
+    @Test
+    void getTopicConsumersShouldUseSelectedInstanceRuntimeClient() {
+        List<TopicConsumerVO> consumers = 
List.of(TopicConsumerVO.builder().group("cg-orders").build());
+        when(runtimeAdminClientResolver.execute(eq("instance-a"), 
any())).thenReturn(consumers);
+        RocketMQMetadataProvider provider = newProvider();
+
+        assertThat(provider.getTopicConsumers("instance-a", 
"orders")).containsExactlyElementsOf(consumers);
+        verify(runtimeAdminClientResolver).execute(eq("instance-a"), any());
+    }
 }
diff --git a/web/src/api/metadata.test.ts b/web/src/api/metadata.test.ts
index 3a57c1bc..d004f440 100644
--- a/web/src/api/metadata.test.ts
+++ b/web/src/api/metadata.test.ts
@@ -52,11 +52,15 @@ describe('topic metadata API', () => {
 
   it('encodes topic names used in path segments', async () => {
     const topicName = '%DLQ%cg-order';
-    mock.onGet('/topics/%25DLQ%25cg-order/routes').reply(200, { code: 200, 
data: [] });
-    mock.onGet('/topics/%25DLQ%25cg-order/consumers').reply(200, { code: 200, 
data: [] });
+    mock
+      .onGet('/topics/%25DLQ%25cg-order/routes', { params: { instanceId: 
'instance-a' } })
+      .reply(200, { code: 200, data: [] });
+    mock
+      .onGet('/topics/%25DLQ%25cg-order/consumers', { params: { instanceId: 
'instance-a' } })
+      .reply(200, { code: 200, data: [] });
 
-    await expect(getTopicRoutes(topicName)).resolves.toEqual([]);
-    await expect(getTopicConsumers(topicName)).resolves.toEqual([]);
+    await expect(getTopicRoutes(topicName, 'instance-a')).resolves.toEqual([]);
+    await expect(getTopicConsumers(topicName, 
'instance-a')).resolves.toEqual([]);
   });
 
   it('persists topic creation, deletion, and sending through API endpoints', 
async () => {
diff --git a/web/src/pages/instance/__tests__/TopicPage.test.tsx 
b/web/src/pages/instance/__tests__/TopicPage.test.tsx
index 9fb9cc26..eaffb8ff 100644
--- a/web/src/pages/instance/__tests__/TopicPage.test.tsx
+++ b/web/src/pages/instance/__tests__/TopicPage.test.tsx
@@ -187,7 +187,23 @@ describe('TopicPage', () => {
 
   it('keeps the current table page after opening and closing topic details', 
async () => {
     const user = userEvent.setup();
-    renderWithProviders();
+    instanceServiceMocks.listInstances.mockResolvedValue([
+      {
+        id: 'instance-a',
+        name: 'Instance A',
+        type: 'DIRECT',
+        endpoint: '127.0.0.1:9876',
+        remark: '',
+        topicCount: 25,
+        consumerGroupCount: 0,
+        createdAt: '2026-01-01T00:00:00Z',
+        updatedAt: '2026-01-01T00:00:00Z',
+      },
+    ]);
+    topicServiceMocks.listTopics.mockResolvedValue(
+      buildTopics(25).map((topic) => ({ ...topic, instanceId: 'instance-a' })),
+    );
+    renderWithProviders('/instance/instance-a/topic');
 
     expect(await screen.findByText('topic-01')).toBeInTheDocument();
 
@@ -200,7 +216,7 @@ describe('TopicPage', () => {
 
     await user.click(screen.getAllByRole('button', { name: /详情/ })[0]);
     await waitFor(() =>
-      
expect(topicServiceMocks.getTopicRoutes).toHaveBeenCalledWith('topic-21', 
'instance-proxy-1'),
+      
expect(topicServiceMocks.getTopicRoutes).toHaveBeenCalledWith('topic-21', 
'instance-a'),
     );
 
     const closeButton = document.querySelector('.ant-modal-close');

Reply via email to