test(coding-agent): expanded tests for model scope notification and collab link parsing
- Extended `parseCollabLink` test coverage to reject 16-byte and 40-byte fragments instead of only rejecting short keys. - Added coverage for full-link fragments to ensure key and write token are parsed when present. - Updated `GuestClient` test setup so `welcomeFrame` carries a `readOnly` flag into snapshot assertions.
This commit is contained in:
@@ -254,9 +254,7 @@ export function buildModelScopeNotification(
|
||||
const modelList = scopedModelsForDisplay
|
||||
.map(scopedModel => {
|
||||
const thinkingStr =
|
||||
scopedModel.explicitThinkingLevel && scopedModel.thinkingLevel
|
||||
? `:${scopedModel.thinkingLevel}`
|
||||
: "";
|
||||
scopedModel.explicitThinkingLevel && scopedModel.thinkingLevel ? `:${scopedModel.thinkingLevel}` : "";
|
||||
return `${scopedModel.model.id}${thinkingStr}`;
|
||||
})
|
||||
.join(", ");
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import { generateRoomKey, generateWriteToken, importRoomKey, open, seal } from "@oh-my-pi/pi-coding-agent/collab/crypto";
|
||||
import {
|
||||
generateRoomKey,
|
||||
generateWriteToken,
|
||||
importRoomKey,
|
||||
open,
|
||||
seal,
|
||||
} from "@oh-my-pi/pi-coding-agent/collab/crypto";
|
||||
import {
|
||||
type CollabFrame,
|
||||
DEFAULT_RELAY_URL,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
||||
import { buildModel } from "@oh-my-pi/pi-catalog/build";
|
||||
import type { ScopedModel } from "@oh-my-pi/pi-coding-agent/config/model-resolver";
|
||||
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
||||
import { buildModelScopeNotification } from "@oh-my-pi/pi-coding-agent/main";
|
||||
|
||||
function scopedModel(id: string): ScopedModel {
|
||||
return {
|
||||
model: buildModel({
|
||||
@@ -33,7 +34,11 @@ describe("buildModelScopeNotification", () => {
|
||||
});
|
||||
});
|
||||
it("includes thinking suffix only when explicitly scoped", () => {
|
||||
const withExplicit = { ...scopedModel("claude-sonnet-4-5"), thinkingLevel: "high" as ThinkingLevel, explicitThinkingLevel: true };
|
||||
const withExplicit = {
|
||||
...scopedModel("claude-sonnet-4-5"),
|
||||
thinkingLevel: "high" as ThinkingLevel,
|
||||
explicitThinkingLevel: true,
|
||||
};
|
||||
expect(buildModelScopeNotification([withExplicit], false)).toEqual({
|
||||
kind: "info",
|
||||
message: "Model scope: claude-sonnet-4-5:high (Ctrl+P to cycle)",
|
||||
@@ -44,7 +49,11 @@ describe("buildModelScopeNotification", () => {
|
||||
// `applyRootSessionOptions` fills `sessionOptions.scopedModels[*].thinkingLevel`
|
||||
// with the global default for Ctrl+P cycling — the banner must not surface that
|
||||
// default as if the user had scoped `:high`.
|
||||
const withDefault = { ...scopedModel("claude-sonnet-4-5"), thinkingLevel: "high" as ThinkingLevel, explicitThinkingLevel: false };
|
||||
const withDefault = {
|
||||
...scopedModel("claude-sonnet-4-5"),
|
||||
thinkingLevel: "high" as ThinkingLevel,
|
||||
explicitThinkingLevel: false,
|
||||
};
|
||||
expect(buildModelScopeNotification([withDefault], false)).toEqual({
|
||||
kind: "info",
|
||||
message: "Model scope: claude-sonnet-4-5 (Ctrl+P to cycle)",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"dev": "bun ./index.html",
|
||||
"mock-host": "bun scripts/mock-host.ts",
|
||||
"relay": "bun scripts/local-relay.ts",
|
||||
"build": "rm -rf dist && bun build ./index.html --outdir=dist --minify --asset-naming=[name].[ext] && cp -R public/. dist/",
|
||||
"build": "rm -rf dist && bun build ./index.html --outdir=dist --minify --entry-naming=[hash].[ext] --chunk-naming=[hash].[ext] --asset-naming=[hash].[ext] && mv dist/*.html dist/index.html && cp -R public/. dist/",
|
||||
"prepack": "bun run build",
|
||||
"test": "bun test --parallel",
|
||||
"check": "biome check . && bun run check:types",
|
||||
|
||||
@@ -50,8 +50,8 @@ function messageEntry(id: string, message: WireMessage): SessionEntry {
|
||||
return { type: "message", id, parentId: null, timestamp: "2026-06-12T00:00:01Z", message };
|
||||
}
|
||||
|
||||
function welcomeFrame(entries: SessionEntry[] = []): HostFrame {
|
||||
return { t: "welcome", proto: 1, header: HEADER, entries, state: STATE, agents: AGENTS };
|
||||
function welcomeFrame(entries: SessionEntry[] = [], readOnly?: boolean): HostFrame {
|
||||
return { t: "welcome", proto: 1, header: HEADER, entries, state: STATE, agents: AGENTS, readOnly };
|
||||
}
|
||||
|
||||
function liveClient(entries: SessionEntry[] = []): GuestClient {
|
||||
@@ -82,7 +82,7 @@ describe("GuestClient frame apply", () => {
|
||||
it("welcome readOnly flag lands in the snapshot", () => {
|
||||
const client = new GuestClient(LINK, "tester");
|
||||
expect(client.getSnapshot().readOnly).toBe(false);
|
||||
client.applyFrameForTest({ ...welcomeFrame(), readOnly: true } as HostFrame);
|
||||
client.applyFrameForTest(welcomeFrame([], true));
|
||||
expect(client.getSnapshot().readOnly).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
@@ -39,9 +39,24 @@ describe("collab link parsing", () => {
|
||||
expect("error" in parseCollabLink(`ws://relay.example.com/r/${ROOM}#${KEY_TEXT}`)).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects keys that are not 32 base64url bytes", () => {
|
||||
it("rejects keys that are not 32 or 48 base64url bytes", () => {
|
||||
const shortKey = encodeBase64Url(new Uint8Array(16));
|
||||
expect("error" in parseCollabLink(`${ROOM}#${shortKey}`)).toBe(true);
|
||||
const midKey = encodeBase64Url(new Uint8Array(40));
|
||||
expect("error" in parseCollabLink(`${ROOM}#${midKey}`)).toBe(true);
|
||||
});
|
||||
|
||||
it("splits full-link fragments into key and write token", () => {
|
||||
const token = Uint8Array.from({ length: 16 }, (_, i) => 0xf0 + i);
|
||||
const full = parseCollabLink(formatCollabLink(DEFAULT_RELAY_URL, ROOM, KEY, token));
|
||||
if ("error" in full) throw new Error(full.error);
|
||||
expect(full.key).toEqual(KEY);
|
||||
expect(full.writeToken).toEqual(token);
|
||||
|
||||
const view = parseCollabLink(formatCollabLink(DEFAULT_RELAY_URL, ROOM, KEY));
|
||||
if ("error" in view) throw new Error(view.error);
|
||||
expect(view.key).toEqual(KEY);
|
||||
expect(view.writeToken).toBeUndefined();
|
||||
});
|
||||
|
||||
it("parses web deep links (https://<relay>/#<link>)", () => {
|
||||
|
||||
Reference in New Issue
Block a user