test(evals): follow actual Files tab before skill Edit

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-11-04 16:35:18 -06:00
1 parent db3f51f5d2
commit 06650ddb38
4 files changed
+18 -5

No files matched your search

+1 -1
View File
@@ -243,7 +243,7 @@ Only `steering.preserve-draft` and `tasks.attachment-brief` may currently declar
`skills.author-skill` v3 follows the normal library card to the exact saved skill.
It accepts the canonical company-scoped detail route or the exact Studio route.
The detail view must expose its normal Edit control. Both paths must show the
The detail view opens Overview first; select Files, then its normal Edit control. Both paths must show the
editable saved checklist, survive reload, and match the same public current
version. The receipt identifies the actual editor surface. The original case
clock, query, and one-human/one-native limits remain unchanged. Older failed
@@ -12,14 +12,15 @@ function fixture(){
const skill={id:"skill",companyId:"company",name:"Website review checklist",slug:"website-review-checklist",editable:true,currentVersionId:"revision",markdown,usedByAgents:[]};
const state:Record<string,unknown>={},o={scenarioId:"skills.author-skill",origin:"https://fixture.test",companyId:"company",leadId:"ceo",state,skills:[skill],versions:{skill:[version]},policy:{},editDecision:{allowed:true},tasks:[],projects:[],goals:[],comments:[],documents:[],revisions:[],humanQueries:["Turn our website review checklist into a reusable skill."],runs:[{id:"native",status:"succeeded",agentId:"ceo",companyId:"company"}],activity:[{action:"company.skill_created",entityId:"skill",agentId:"ceo"}],links:[],reply:"Created the reusable company skill, saved in the library and not assigned to any agent."} as unknown as InternalObservation;
observed.base=o;
const ui={library:true,studio:true,editable:true,body:markdown,changedAfterReload:false,wrongRoute:false,foreignRoute:false,directStudio:false,delayedHydration:false,inEdit:false};const events:string[]=[];
const ui={library:true,studio:true,editable:true,body:markdown,changedAfterReload:false,wrongRoute:false,foreignRoute:false,directStudio:false,delayedHydration:false,inEdit:false,filesSelected:false};const events:string[]=[];
const editor={get visible(){return ui.studio && (ui.inEdit || ui.directStudio);},get editable(){return ui.editable;},locator:()=>({evaluateAll:async()=>ui.delayedHydration&&editorReads++===0?[]:(ui.changedAfterReload&&reloads?"Lost checklist":ui.body).split("\n")})};
const page={url:()=>current,getByRole:(role:string,options?:{name?:string})=>{
if(role==="textbox")return editor;
if(role==="button" && options?.name==="Edit")return{click:async()=>{if(!ui.editable)throw Error("No Edit control");ui.inEdit=true;events.push("Edit");}};
if(role==="tab" && options?.name==="Files")return{click:async()=>{ui.filesSelected=true;events.push("Files");}};
if(role==="button" && options?.name==="Edit")return{click:async()=>{if(!ui.editable||!ui.filesSelected)throw Error("No Edit control outside Files");ui.inEdit=true;events.push("Edit");}};
if(role==="link")return{first:()=>({click:async()=>{events.push(options!.name!);current=options?.name==="Skills"?"https://fixture.test/ACORN/skills":"https://fixture.test/ACORN/skills/studio";}})};
return{filter:()=>({first:()=>({get visible(){return ui.library;},click:async()=>{events.push("open-skill");current=ui.foreignRoute?"https://fixture.test/FOREIGN/skills/website-review-checklist":ui.wrongRoute?"https://fixture.test/ACORN/skills/other":ui.directStudio?"https://fixture.test/ACORN/skills/studio/skill":"https://fixture.test/ACORN/skills/website-review-checklist";}})})};
},getByText:()=>({first:()=>({get visible(){return ui.studio;}})}),getByTestId:()=>({get visible(){return current===source;}}),reload:async()=>{reloads++;ui.inEdit=false;events.push("reload");},goto:async(url:string)=>{current=url;events.push("return-chat");}};
},getByText:()=>({first:()=>({get visible(){return ui.studio;}})}),getByTestId:()=>({get visible(){return current===source;}}),reload:async()=>{reloads++;ui.inEdit=false;ui.filesSelected=false;events.push("reload");},goto:async(url:string)=>{current=url;events.push("return-chat");}};
const after=structuredClone(skill),get=vi.fn(async(route:string)=>{
if(route.endsWith("/skills"))return[{id:"skill"}];
if(route.endsWith("/skills/skill"))return after;
@@ -34,7 +35,7 @@ function fixture(){
it("the actual authoring act performs nonmutating canonical-library/Edit inspection and keeps a single native/human turn",async()=>{
const f=fixture(),d=integratorSkillsCases.find(x=>x.scenarioId==="skills.author-skill")!;
await d.act!(f.ctx,f.state);
expect(f.events).toEqual(["Skills","My Skills","open-skill","Edit","reload","Edit","return-chat"]);
expect(f.events).toEqual(["Skills","My Skills","open-skill","Files","Edit","reload","Files","Edit","return-chat"]);
expect(f.state.authoredSkillInspection).toMatchObject({skillId:"skill",versionId:"revision",editorSurface:"detail",editorVisible:true,readbackMatched:true});
expect(gradeIntegratorSkills({...f.o,state:f.state}).passed).toBe(true);
expect(d.expectedRunCount).toBe(1);expect(d.expectedHumanMessageCount).toBe(1);
@@ -119,6 +119,7 @@ export async function inspectAuthoredSkill(ctx: ChatCatalogContext, state: Recor
await expect(ctx.input.page).toHaveURL(url => url.origin === new URL(source).origin
&& (url.pathname === studioRoute || url.pathname === detailRoute), { timeout: remaining() });
if (new URL(ctx.input.page.url()).pathname === detailRoute) {
await ctx.input.page.getByRole("tab", { name: "Files", exact: true }).click({ timeout: remaining() });
await ctx.input.page.getByRole("button", { name: "Edit", exact: true }).click({ timeout: remaining() });
}
};
+11
View File
@@ -1154,3 +1154,14 @@ describe("install-time agent enablement", () => {
expect(onConfirm).toHaveBeenCalledWith({ slug: "wireframe", force: false, agentIds: [] });
});
});
it.each(["overview", "files"] as const)("exposes the real named Edit control only in the %s tab", async activeTab => {
const version = makeVersion(1, "# Demo skill\n\nSaved body");
const setEditMode = vi.fn();
const node = await renderSkillDetail([version], { activeTab, setEditMode,
file: { skillId: "skill-1", path: "SKILL.md", kind: "skill", content: "# Demo skill\n\nSaved body", language: "markdown", markdown: true, editable: true, encoding: "utf8" } });
expect(buttonsNamed(node, "Files")).toHaveLength(1);
const edit = buttonsNamed(node, "Edit");
expect(edit).toHaveLength(activeTab === "files" ? 1 : 0);
if (activeTab === "files") { await click(edit[0]!); expect(setEditMode).toHaveBeenCalledExactlyOnceWith(true); }
});