fix: 展示 JavaScript 代码节点执行错误

- 配置脚本执行超时并保留可定位的 JavaScript 异常信息

- 在试运行步骤和终态结果中展示并展开失败节点
This commit is contained in:
2026-08-03 11:17:44 +08:00
parent 1bf755f6c4
commit dc99d1aa52
9 changed files with 273 additions and 30 deletions

View File

@@ -0,0 +1,49 @@
package tech.easyflow.ai.config;
import org.junit.Assert;
import org.junit.Test;
/**
* JavaScript 代码执行引擎配置测试。
*/
public class JavascriptCodeEnginePropsTest {
/**
* 验证正数超时配置可以正常写入。
*/
@Test
public void shouldAcceptPositiveTimeout() {
JavascriptCodeEngineProps props =
new JavascriptCodeEngineProps();
props.setTimeoutMs(1000L);
Assert.assertEquals(1000L, props.getTimeoutMs());
}
/**
* 验证非正数超时配置会立即失败。
*/
@Test
public void shouldRejectNonPositiveTimeout() {
assertInvalidTimeout(0L);
assertInvalidTimeout(-1L);
}
/**
* 验证指定超时值无法写入配置。
*
* @param timeoutMs 非法超时值
*/
private void assertInvalidTimeout(long timeoutMs) {
JavascriptCodeEngineProps props =
new JavascriptCodeEngineProps();
try {
props.setTimeoutMs(timeoutMs);
Assert.fail("非正数超时配置应执行失败");
} catch (IllegalArgumentException exception) {
Assert.assertTrue(exception.getMessage().contains(
"必须大于 0"));
}
}
}

View File

@@ -2,11 +2,13 @@ package tech.easyflow.ai.easyagentsflow.service;
import com.easyagents.flow.core.chain.ChainState;
import com.easyagents.flow.core.chain.ChainStatus;
import com.easyagents.flow.core.chain.ExceptionSummary;
import com.easyagents.flow.core.chain.NodeState;
import com.easyagents.flow.core.chain.NodeStatus;
import com.easyagents.flow.core.chain.repository.ChainStateRepository;
import com.easyagents.flow.core.chain.repository.NodeStateRepository;
import com.easyagents.flow.core.chain.runtime.ChainExecutor;
import com.easyagents.flow.core.code.impl.JavascriptExecutionException;
import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.ai.easyagentsflow.entity.ChainInfo;
@@ -137,6 +139,50 @@ public class TinyFlowServiceTest {
.load(EXECUTE_ID, NODE_ID);
}
/**
* 验证 JavaScript 执行错误使用面向试运行用户的定位信息。
*
* @throws Exception 测试依赖注入失败时抛出
*/
@Test
public void shouldExposeJavascriptExecutionMessage()
throws Exception {
ChainExecutor chainExecutor = mock(ChainExecutor.class);
ChainStateRepository chainStateRepository =
mock(ChainStateRepository.class);
NodeStateRepository nodeStateRepository =
mock(NodeStateRepository.class);
String message =
"JavaScript 语法错误(第 2 行,第 3 列Unexpected token";
ExceptionSummary error = new ExceptionSummary(
new JavascriptExecutionException(
message,
new IllegalArgumentException("raw parser error")));
ChainState chainState = new ChainState();
chainState.setStatus(ChainStatus.FAILED);
chainState.setError(error);
NodeState nodeState = new NodeState();
nodeState.setStatus(NodeStatus.FAILED);
nodeState.setError(error);
when(chainExecutor.getChainStateRepository())
.thenReturn(chainStateRepository);
when(chainExecutor.getNodeStateRepository())
.thenReturn(nodeStateRepository);
when(chainStateRepository.load(EXECUTE_ID))
.thenReturn(chainState);
when(nodeStateRepository.load(EXECUTE_ID, NODE_ID))
.thenReturn(nodeState);
TinyFlowService service = service(chainExecutor);
ChainInfo result = service.getChainStatus(
EXECUTE_ID, List.of(node(NodeStatus.READY)));
Assert.assertEquals(message, result.getMessage());
Assert.assertEquals(
message,
result.getNodes().get(NODE_ID).getMessage());
}
/**
* 创建带指定初始状态的设计器节点。
*