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

dengliming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu-dashboard.git


The following commit(s) were added to refs/heads/master by this push:
     new 81c7ec42 fix: preserve API debug mock state (#687)
81c7ec42 is described below

commit 81c7ec42d7e20b5cd7f91115f7393054562710a7
Author: Carlos Acosta <[email protected]>
AuthorDate: Sun Sep 27 22:32:55 2026 -0500

    fix: preserve API debug mock state (#687)
    
    * fix: preserve API debug mock state
    
    Co-authored-by: Aeontra <aeontra@localhost>
    
    * fix: invalidate stale API mock identity
    
    Co-authored-by: Aeontra <aeontra@localhost>
    
    ---------
    
    Co-authored-by: Aeontra <aeontra@localhost>
---
 src/routes/Document/components/ApiDebug.js         |   9 +-
 .../Document/components/ApiDebug.state.test.js     | 158 +++++++++++++++++++++
 2 files changed, 165 insertions(+), 2 deletions(-)

diff --git a/src/routes/Document/components/ApiDebug.js 
b/src/routes/Document/components/ApiDebug.js
index ee196954..3098c512 100644
--- a/src/routes/Document/components/ApiDebug.js
+++ b/src/routes/Document/components/ApiDebug.js
@@ -145,8 +145,13 @@ const FCForm = forwardRef(({ form, onSubmit }, ref) => {
   }, [apiDetail.httpMethod]);
 
   useEffect(() => {
-    setInitialValue({ url: apiDetail.apiPath });
-  }, [apiDetail.apiPath]);
+    setInitialValue((prev) => ({
+      ...prev,
+      id: prev.apiId === apiDetail.id ? prev.id : null,
+      apiId: apiDetail.id,
+      url: apiDetail.apiPath,
+    }));
+  }, [apiDetail.id, apiDetail.apiPath]);
 
   useEffect(() => {
     form.setFieldsValue({
diff --git a/src/routes/Document/components/ApiDebug.state.test.js 
b/src/routes/Document/components/ApiDebug.state.test.js
new file mode 100644
index 00000000..31422397
--- /dev/null
+++ b/src/routes/Document/components/ApiDebug.state.test.js
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from "react";
+import { fireEvent, render, screen, waitFor } from "@testing-library/react";
+import { deleteMockRequest } from "../../../services/api";
+import ApiContext from "./ApiContext";
+import ApiDebug from "./ApiDebug";
+
+jest.mock("antd", () => {
+  const ReactModule = jest.requireActual("react");
+  const antd = jest.requireActual("antd");
+  antd.Input.Group = ReactModule.forwardRef((props, ref) =>
+    ReactModule.createElement("div", {
+      ref,
+      "data-input-group": Boolean(props),
+    }),
+  );
+  return {
+    ...antd,
+    message: {
+      error: jest.fn(),
+      success: jest.fn(),
+      warn: jest.fn(),
+    },
+  };
+});
+
+jest.mock("dva/fetch", () => jest.fn());
+jest.mock("react-html-parser", () => jest.fn(() => null));
+jest.mock("react-json-view", () => () => null);
+jest.mock("./HeadersEditor", () => {
+  const ReactModule = jest.requireActual("react");
+  return ReactModule.forwardRef((props, ref) =>
+    ReactModule.createElement("div", {
+      ref,
+      "data-headers-editor": Boolean(props),
+    }),
+  );
+});
+jest.mock(
+  "../../../utils/AuthButton",
+  () =>
+    ({ children }) =>
+      children,
+);
+jest.mock("../../../utils/IntlUtils", () => ({
+  getIntlContent: (key) => key,
+}));
+
+jest.mock("../../../services/api", () => ({
+  createOrUpdateMockRequest: jest.fn(),
+  deleteMockRequest: jest.fn(),
+  getApiMockRequest: jest.fn(),
+  sandboxProxyGateway: jest.fn(() => "/sandbox"),
+}));
+
+it("keeps the saved mock id when the API path effect runs", async () => {
+  deleteMockRequest.mockResolvedValue({ code: 200, message: "Deleted" });
+
+  render(
+    <ApiContext.Provider
+      value={{
+        apiData: { envProps: [] },
+        apiDetail: {
+          apiPath: "/users",
+          httpMethod: 0,
+          id: "api-1",
+        },
+        apiMock: {
+          body: "{}",
+          header: { "X-Test": "value" },
+          host: "api.example.com",
+          id: "mock-1",
+          pathVariable: "",
+          port: "443",
+          query: "[]",
+          url: "https://api.example.com/users";,
+        },
+      }}
+    >
+      <ApiDebug />
+    </ApiContext.Provider>,
+  );
+
+  fireEvent.click(screen.getByText("SHENYU.DOCUMENT.APIDOC.DEBUG.MOCK.RESET"));
+
+  await waitFor(() => {
+    expect(deleteMockRequest).toHaveBeenCalledWith("mock-1");
+  });
+});
+
+it("does not delete the previous API mock while the next API mock is loading", 
async () => {
+  deleteMockRequest.mockResolvedValue({ code: 200, message: "Deleted" });
+
+  const apiMock = {
+    body: "{}",
+    header: { "X-Test": "value" },
+    host: "api.example.com",
+    id: "mock-a",
+    pathVariable: "",
+    port: "443",
+    query: "[]",
+    url: "https://api.example.com/a";,
+  };
+  const apiData = { envProps: [] };
+  const { rerender } = render(
+    <ApiContext.Provider
+      value={{
+        apiData,
+        apiDetail: {
+          apiPath: "/a",
+          httpMethod: 0,
+          id: "api-a",
+        },
+        apiMock,
+      }}
+    >
+      <ApiDebug />
+    </ApiContext.Provider>,
+  );
+
+  rerender(
+    <ApiContext.Provider
+      value={{
+        apiData,
+        apiDetail: {
+          apiPath: "/b",
+          httpMethod: 0,
+          id: "api-b",
+        },
+        apiMock,
+      }}
+    >
+      <ApiDebug />
+    </ApiContext.Provider>,
+  );
+
+  fireEvent.click(screen.getByText("SHENYU.DOCUMENT.APIDOC.DEBUG.MOCK.RESET"));
+
+  await waitFor(() => {
+    expect(deleteMockRequest).not.toHaveBeenCalled();
+  });
+});

Reply via email to