test: isolate line jiti runtime smoke

This commit is contained in:
Peter Steinberger 2026-03-24 02:38:09 +00:00
parent 9e8abb468d
commit d8e77c423a
1 changed files with 164 additions and 28 deletions

View File

@ -1,32 +1,165 @@
import { execFileSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
describe("line runtime api", () => {
it("loads through Jiti without duplicate export errors", () => {
const root = process.cwd();
const runtimeApiPath = path.join(root, "extensions", "line", "runtime-api.ts");
const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-line-jiti-"));
const runtimeApiPath = path.join(fixtureRoot, "runtime-api.ts");
const pluginSdkRoot = path.join(fixtureRoot, "plugin-sdk");
fs.mkdirSync(pluginSdkRoot, { recursive: true });
const writeFile = (relativePath: string, contents: string) => {
const filePath = path.join(fixtureRoot, relativePath);
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, contents, "utf8");
return filePath;
};
const botAccessPath = writeFile(
"src/bot-access.js",
`export const firstDefined = (...values) => values.find((value) => value !== undefined);
export const isSenderAllowed = () => true;
export const normalizeAllowFrom = (value) => value;
export const normalizeDmAllowFromWithStore = (value) => value;
`,
);
const downloadPath = writeFile(
"src/download.js",
`export const downloadLineMedia = () => "downloaded";
`,
);
const probePath = writeFile(
"src/probe.js",
`export const probeLineBot = () => "probed";
`,
);
const templateMessagesPath = writeFile(
"src/template-messages.js",
`export const buildTemplateMessageFromPayload = () => ({ type: "template" });
`,
);
const sendPath = writeFile(
"src/send.js",
`export const createQuickReplyItems = () => [];
export const pushFlexMessage = () => "flex";
export const pushLocationMessage = () => "location";
export const pushMessageLine = () => "push";
export const pushMessagesLine = () => "pushMany";
export const pushTemplateMessage = () => "template";
export const pushTextMessageWithQuickReplies = () => "quick";
export const sendMessageLine = () => "send";
`,
);
const writePluginSdkShim = (subpath: string, contents: string) => {
writeFile(path.join("plugin-sdk", `${subpath}.ts`), contents);
};
writePluginSdkShim(
"core",
`export const clearAccountEntryFields = () => ({});
`,
);
writePluginSdkShim(
"channel-config-schema",
`export const buildChannelConfigSchema = () => ({});
`,
);
writePluginSdkShim(
"reply-runtime",
`export {};
`,
);
writePluginSdkShim(
"testing",
`export {};
`,
);
writePluginSdkShim(
"channel-contract",
`export {};
`,
);
writePluginSdkShim(
"setup",
`export const DEFAULT_ACCOUNT_ID = "default";
export const formatDocsLink = (href, fallback) => href ?? fallback;
export const setSetupChannelEnabled = () => {};
export const splitSetupEntries = (entries) => entries;
`,
);
writePluginSdkShim(
"status-helpers",
`export const buildComputedAccountStatusSnapshot = () => ({});
export const buildTokenChannelStatusSummary = () => "ok";
`,
);
writePluginSdkShim(
"line-runtime",
`export { firstDefined, isSenderAllowed, normalizeAllowFrom, normalizeDmAllowFromWithStore } from ${JSON.stringify(botAccessPath)};
export { downloadLineMedia } from ${JSON.stringify(downloadPath)};
export { probeLineBot } from ${JSON.stringify(probePath)};
export { buildTemplateMessageFromPayload } from ${JSON.stringify(templateMessagesPath)};
export {
createQuickReplyItems,
pushFlexMessage,
pushLocationMessage,
pushMessageLine,
pushMessagesLine,
pushTemplateMessage,
pushTextMessageWithQuickReplies,
sendMessageLine,
} from ${JSON.stringify(sendPath)};
`,
);
fs.writeFileSync(
runtimeApiPath,
`export { clearAccountEntryFields } from "openclaw/plugin-sdk/core";
export { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
export { buildComputedAccountStatusSnapshot, buildTokenChannelStatusSummary } from "openclaw/plugin-sdk/status-helpers";
export { DEFAULT_ACCOUNT_ID, formatDocsLink, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
export { firstDefined, isSenderAllowed, normalizeAllowFrom, normalizeDmAllowFromWithStore } from ${JSON.stringify(botAccessPath)};
export { downloadLineMedia } from ${JSON.stringify(downloadPath)};
export { probeLineBot } from ${JSON.stringify(probePath)};
export { buildTemplateMessageFromPayload } from ${JSON.stringify(templateMessagesPath)};
export {
createQuickReplyItems,
pushFlexMessage,
pushLocationMessage,
pushMessageLine,
pushMessagesLine,
pushTemplateMessage,
pushTextMessageWithQuickReplies,
sendMessageLine,
} from ${JSON.stringify(sendPath)};
export * from "openclaw/plugin-sdk/line-runtime";
`,
"utf8",
);
const script = `
import fs from "node:fs";
import path from "node:path";
import { createJiti } from "jiti";
const root = ${JSON.stringify(root)};
const runtimeApiPath = ${JSON.stringify(runtimeApiPath)};
const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
const exportedSubpaths = Object.keys(pkg.exports ?? {})
.filter((key) => key.startsWith("./plugin-sdk/"))
.map((key) => key.slice("./plugin-sdk/".length))
.filter((name) => name && !name.includes("/"));
const aliasEntries = exportedSubpaths.map((name) => {
const distPath = path.join(root, "dist", "plugin-sdk", name + ".js");
const srcPath = path.join(root, "src", "plugin-sdk", name + ".ts");
return [
"openclaw/plugin-sdk/" + name,
fs.existsSync(distPath) ? distPath : srcPath,
];
});
const alias = Object.fromEntries(aliasEntries);
const pluginSdkRoot = ${JSON.stringify(pluginSdkRoot)};
const alias = Object.fromEntries([
"core",
"channel-config-schema",
"reply-runtime",
"testing",
"channel-contract",
"setup",
"status-helpers",
"line-runtime",
].map((name) => ["openclaw/plugin-sdk/" + name, path.join(pluginSdkRoot, name + ".ts")]));
const jiti = createJiti(path.join(root, "openclaw.mjs"), {
interopDefault: true,
tryNative: false,
@ -46,17 +179,20 @@ console.log(
}),
);
`;
const raw = execFileSync(process.execPath, ["--input-type=module", "--eval", script], {
cwd: root,
encoding: "utf-8",
});
expect(JSON.parse(raw)).toEqual({
buildTemplateMessageFromPayload: "function",
downloadLineMedia: "function",
isSenderAllowed: "function",
probeLineBot: "function",
pushMessageLine: "function",
});
try {
const raw = execFileSync(process.execPath, ["--input-type=module", "--eval", script], {
cwd: root,
encoding: "utf-8",
});
expect(JSON.parse(raw)).toEqual({
buildTemplateMessageFromPayload: "function",
downloadLineMedia: "function",
isSenderAllowed: "function",
probeLineBot: "function",
pushMessageLine: "function",
});
} finally {
fs.rmSync(fixtureRoot, { recursive: true, force: true });
}
}, 240_000);
});