阶段1-rpa-core建包: engine+31个纯Node能力迁入packages/rpa-core, 领域类型单一源化, createEngine工厂收拢模块级状态
- engine/(registry/types/runtime/expression)物理迁入包, 解耦shared/types(域类型归包, 宿主type-only re-export) - 31个纯Node能力+27个测试迁入包; 宿主留守Electron/浏览器/AI依赖能力, index.ts经@rpa/core/capabilities拉起 - 新增createEngine()/defaultEngine: excel缓存/Excel句柄/db连接/FTP客户端/OCR实例/拟真设置挂引擎实例 - remaining-core子流程依赖改为host-bridge注入, 包内不再import宿主flows - 宿主main/index.ts启动时注入子流程源; electron-vite/vitest/tsconfig配@rpa/core源码别名 - 验证: typecheck绿, 快照909个id diff为零, 332测试过(2个桌面冒烟因会话无交互SetForegroundWindow被拒, 环境阻塞)
This commit is contained in:
1 parent
4139400dbd
commit
caa8e19332
111 files changed
+581
-337
No files matched your search
@@ -0,0 +1,67 @@
|
||||
import net from "node:net";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import type { CatalogComponent, FlowNode } from "../types";
|
||||
import type { RunContext } from "../engine/types";
|
||||
import { getHandler, hasCapability } from "../engine/registry";
|
||||
import "./message";
|
||||
|
||||
const context = {} as RunContext;
|
||||
const component = {} as CatalogComponent;
|
||||
const node = (id: string): FlowNode => ({ id, componentId: id, position: { x: 0, y: 0 }, values: {}, options: {} });
|
||||
const ids = [
|
||||
"Mail_FindMail", "Mail_FindMail_v1", "Mail_FindMail_v2",
|
||||
"Mail_ReplyMail", "Mail_ReplyMail_v1", "Mail_ReplyMail_v2",
|
||||
"Mail_DoGetMailMessage", "Mail_DoGetMailMessage_v1", "Mail_DoGetMailMessage_v2"
|
||||
];
|
||||
|
||||
afterEach(async () => {});
|
||||
|
||||
describe("mail receive and reply", () => {
|
||||
it("registers find, reply and Outlook message capabilities", () => {
|
||||
for (const id of ids) expect(hasCapability(id), id).toBe(true);
|
||||
});
|
||||
|
||||
it("replies through SMTP with the selected mail sender", async () => {
|
||||
let received = "";
|
||||
const server = net.createServer((socket) => {
|
||||
socket.setEncoding("utf8");
|
||||
socket.write("220 localhost ESMTP\r\n");
|
||||
let buffer = "";
|
||||
let dataMode = false;
|
||||
socket.on("data", (chunk) => {
|
||||
buffer += chunk;
|
||||
const lines = buffer.split("\r\n");
|
||||
buffer = lines.pop() || "";
|
||||
for (const line of lines) {
|
||||
if (dataMode) {
|
||||
if (line === ".") {
|
||||
dataMode = false;
|
||||
socket.write("250 queued\r\n");
|
||||
} else received += line + "\n";
|
||||
} else if (/^EHLO/i.test(line)) socket.write("250-localhost\r\n250 OK\r\n");
|
||||
else if (/^MAIL FROM/i.test(line)) socket.write("250 ok\r\n");
|
||||
else if (/^RCPT TO/i.test(line)) socket.write("250 ok\r\n");
|
||||
else if (/^DATA/i.test(line)) { dataMode = true; socket.write("354 end with dot\r\n"); }
|
||||
else if (/^QUIT/i.test(line)) { socket.write("221 bye\r\n"); socket.end(); }
|
||||
else socket.write("250 OK\r\n");
|
||||
}
|
||||
});
|
||||
});
|
||||
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
||||
const port = (server.address() as net.AddressInfo).port;
|
||||
try {
|
||||
const handler = getHandler("Mail_ReplyMail_v2");
|
||||
expect(handler).toBeTruthy();
|
||||
const result = await handler!(context, node("Mail_ReplyMail_v2"), {
|
||||
account_obj: { host: "127.0.0.1", port, account: "robot@example.com", secure: "False" },
|
||||
mail_obj: { from: "owner@example.com", subject: "status", messageId: "<abc@example.com>" },
|
||||
content: "reply delivered"
|
||||
}, component);
|
||||
expect(result).toMatchObject({ accepted: ["owner@example.com"] });
|
||||
expect(received).toContain("reply delivered");
|
||||
expect(received).toContain("Re: status");
|
||||
} finally {
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
}
|
||||
}, 30000);
|
||||
});
|
||||
Reference in new issue
Block a user