mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 11:50:42 +00:00
test: tighten extension helper assertions
This commit is contained in:
@@ -4,6 +4,8 @@ import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plug
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { normalizeUrlPath, resolveFileWithinRoot } from "./file-resolver.js";
|
||||
|
||||
type ResolvedFile = NonNullable<Awaited<ReturnType<typeof resolveFileWithinRoot>>>;
|
||||
|
||||
async function withCanvasTemp<T>(prefix: string, run: (dir: string) => Promise<T>): Promise<T> {
|
||||
return await withTempWorkspace(
|
||||
{ rootDir: resolvePreferredOpenClawTmpDir(), prefix },
|
||||
@@ -11,6 +13,16 @@ async function withCanvasTemp<T>(prefix: string, run: (dir: string) => Promise<T
|
||||
);
|
||||
}
|
||||
|
||||
function expectResolvedFile(
|
||||
result: Awaited<ReturnType<typeof resolveFileWithinRoot>>,
|
||||
): ResolvedFile {
|
||||
expect(result).toEqual(expect.objectContaining({ handle: expect.any(Object) }));
|
||||
if (result === null) {
|
||||
throw new Error("Expected resolved file within root");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
describe("resolveFileWithinRoot", () => {
|
||||
it("normalizes URL paths", () => {
|
||||
expect(normalizeUrlPath("/nested/../file.txt")).toBe("/file.txt");
|
||||
@@ -23,11 +35,11 @@ describe("resolveFileWithinRoot", () => {
|
||||
await fs.writeFile(path.join(root, "docs", "index.html"), "<h1>docs</h1>");
|
||||
|
||||
const result = await resolveFileWithinRoot(root, "/docs");
|
||||
expect(result).not.toBeNull();
|
||||
const resolved = expectResolvedFile(result);
|
||||
try {
|
||||
await expect(result?.handle.readFile({ encoding: "utf8" })).resolves.toBe("<h1>docs</h1>");
|
||||
await expect(resolved.handle.readFile({ encoding: "utf8" })).resolves.toBe("<h1>docs</h1>");
|
||||
} finally {
|
||||
await result?.handle.close().catch(() => {});
|
||||
await resolved.handle.close().catch(() => {});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
resolveCodexTrajectoryPointerFlags,
|
||||
} from "./trajectory.js";
|
||||
|
||||
type CodexTrajectoryRecorder = NonNullable<ReturnType<typeof createCodexTrajectoryRecorder>>;
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
function makeTempDir(): string {
|
||||
@@ -22,6 +24,16 @@ afterEach(() => {
|
||||
}
|
||||
});
|
||||
|
||||
function expectTrajectoryRecorder(
|
||||
recorder: ReturnType<typeof createCodexTrajectoryRecorder>,
|
||||
): CodexTrajectoryRecorder {
|
||||
expect(recorder).toEqual(expect.objectContaining({ recordEvent: expect.any(Function) }));
|
||||
if (recorder === null) {
|
||||
throw new Error("Expected Codex trajectory recorder");
|
||||
}
|
||||
return recorder;
|
||||
}
|
||||
|
||||
describe("Codex trajectory recorder", () => {
|
||||
it("keeps write flags usable when O_NOFOLLOW is unavailable", () => {
|
||||
const constants = {
|
||||
@@ -52,13 +64,13 @@ describe("Codex trajectory recorder", () => {
|
||||
env: {},
|
||||
});
|
||||
|
||||
expect(recorder).not.toBeNull();
|
||||
recorder?.recordEvent("session.started", {
|
||||
const trajectoryRecorder = expectTrajectoryRecorder(recorder);
|
||||
trajectoryRecorder.recordEvent("session.started", {
|
||||
apiKey: "secret",
|
||||
headers: [{ name: "Authorization", value: "Bearer sk-test-secret-token" }],
|
||||
command: "curl -H 'Authorization: Bearer sk-other-secret-token'",
|
||||
});
|
||||
await recorder?.flush();
|
||||
await trajectoryRecorder.flush();
|
||||
|
||||
const filePath = path.join(tmpDir, "session.trajectory.jsonl");
|
||||
const content = fs.readFileSync(filePath, "utf8");
|
||||
@@ -82,8 +94,9 @@ describe("Codex trajectory recorder", () => {
|
||||
env: { OPENCLAW_TRAJECTORY_DIR: tmpDir },
|
||||
});
|
||||
|
||||
recorder?.recordEvent("session.started");
|
||||
await recorder?.flush();
|
||||
const trajectoryRecorder = expectTrajectoryRecorder(recorder);
|
||||
trajectoryRecorder.recordEvent("session.started");
|
||||
await trajectoryRecorder.flush();
|
||||
|
||||
expect(fs.existsSync(path.join(tmpDir, "___evil_session.jsonl"))).toBe(true);
|
||||
});
|
||||
@@ -119,8 +132,9 @@ describe("Codex trajectory recorder", () => {
|
||||
env: {},
|
||||
});
|
||||
|
||||
recorder?.recordEvent("session.started");
|
||||
await recorder?.flush();
|
||||
const trajectoryRecorder = expectTrajectoryRecorder(recorder);
|
||||
trajectoryRecorder.recordEvent("session.started");
|
||||
await trajectoryRecorder.flush();
|
||||
|
||||
expect(fs.existsSync(path.join(targetDir, "session.trajectory.jsonl"))).toBe(false);
|
||||
});
|
||||
@@ -137,12 +151,13 @@ describe("Codex trajectory recorder", () => {
|
||||
env: {},
|
||||
});
|
||||
|
||||
recorder?.recordEvent("context.compiled", {
|
||||
const trajectoryRecorder = expectTrajectoryRecorder(recorder);
|
||||
trajectoryRecorder.recordEvent("context.compiled", {
|
||||
fields: Object.fromEntries(
|
||||
Array.from({ length: 100 }, (_, index) => [`field-${index}`, "x".repeat(3_000)]),
|
||||
),
|
||||
});
|
||||
await recorder?.flush();
|
||||
await trajectoryRecorder.flush();
|
||||
|
||||
const parsed = JSON.parse(
|
||||
fs.readFileSync(path.join(tmpDir, "session.trajectory.jsonl"), "utf8"),
|
||||
|
||||
@@ -1,44 +1,61 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveDiscordPresenceUpdate } from "./presence.js";
|
||||
|
||||
type DiscordPresenceUpdate = NonNullable<ReturnType<typeof resolveDiscordPresenceUpdate>>;
|
||||
|
||||
function expectPresenceUpdate(
|
||||
result: ReturnType<typeof resolveDiscordPresenceUpdate>,
|
||||
): DiscordPresenceUpdate {
|
||||
expect(result).toEqual(expect.objectContaining({ activities: expect.any(Array) }));
|
||||
if (result === null) {
|
||||
throw new Error("Expected Discord presence update");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
describe("resolveDiscordPresenceUpdate", () => {
|
||||
it("returns online presence when no config is provided", () => {
|
||||
const result = resolveDiscordPresenceUpdate({});
|
||||
expect(result).not.toBeNull();
|
||||
expect(result!.status).toBe("online");
|
||||
expect(result!.activities).toEqual([]);
|
||||
const result = expectPresenceUpdate(resolveDiscordPresenceUpdate({}));
|
||||
expect(result.status).toBe("online");
|
||||
expect(result.activities).toEqual([]);
|
||||
});
|
||||
|
||||
it("uses configured status", () => {
|
||||
const result = resolveDiscordPresenceUpdate({ status: "dnd" });
|
||||
expect(result!.status).toBe("dnd");
|
||||
const result = expectPresenceUpdate(resolveDiscordPresenceUpdate({ status: "dnd" }));
|
||||
expect(result.status).toBe("dnd");
|
||||
});
|
||||
|
||||
it("includes activity when configured", () => {
|
||||
const result = resolveDiscordPresenceUpdate({ activity: "Helping humans" });
|
||||
expect(result!.status).toBe("online");
|
||||
expect(result!.activities).toHaveLength(1);
|
||||
expect(result!.activities[0].state).toBe("Helping humans");
|
||||
const result = expectPresenceUpdate(
|
||||
resolveDiscordPresenceUpdate({ activity: "Helping humans" }),
|
||||
);
|
||||
expect(result.status).toBe("online");
|
||||
expect(result.activities).toHaveLength(1);
|
||||
expect(result.activities[0].state).toBe("Helping humans");
|
||||
});
|
||||
|
||||
it("uses custom activity type by default", () => {
|
||||
const result = resolveDiscordPresenceUpdate({ activity: "test" });
|
||||
expect(result!.activities[0].type).toBe(4);
|
||||
expect(result!.activities[0].name).toBe("Custom Status");
|
||||
const result = expectPresenceUpdate(resolveDiscordPresenceUpdate({ activity: "test" }));
|
||||
expect(result.activities[0].type).toBe(4);
|
||||
expect(result.activities[0].name).toBe("Custom Status");
|
||||
});
|
||||
|
||||
it("respects explicit activityType", () => {
|
||||
const result = resolveDiscordPresenceUpdate({ activity: "test", activityType: 3 });
|
||||
expect(result!.activities[0].type).toBe(3);
|
||||
expect(result!.activities[0].name).toBe("test");
|
||||
const result = expectPresenceUpdate(
|
||||
resolveDiscordPresenceUpdate({ activity: "test", activityType: 3 }),
|
||||
);
|
||||
expect(result.activities[0].type).toBe(3);
|
||||
expect(result.activities[0].name).toBe("test");
|
||||
});
|
||||
|
||||
it("sets streaming URL for type 1", () => {
|
||||
const result = resolveDiscordPresenceUpdate({
|
||||
activity: "Live",
|
||||
activityType: 1,
|
||||
activityUrl: "https://twitch.tv/test",
|
||||
});
|
||||
expect(result!.activities[0].url).toBe("https://twitch.tv/test");
|
||||
const result = expectPresenceUpdate(
|
||||
resolveDiscordPresenceUpdate({
|
||||
activity: "Live",
|
||||
activityType: 1,
|
||||
activityUrl: "https://twitch.tv/test",
|
||||
}),
|
||||
);
|
||||
expect(result.activities[0].url).toBe("https://twitch.tv/test");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,9 +3,11 @@ import type { ResolvedMemoryWikiConfig } from "./config.js";
|
||||
import { createWikiApplyTool } from "./tool.js";
|
||||
|
||||
function asSchemaObject(value: unknown): Record<string, unknown> {
|
||||
expect(typeof value).toBe("object");
|
||||
expect(value).not.toBeNull();
|
||||
expect(value).toEqual(expect.any(Object));
|
||||
expect(Array.isArray(value)).toBe(false);
|
||||
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
||||
throw new Error("Expected JSON schema object");
|
||||
}
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user