mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 08:01:25 +00:00
287 lines
10 KiB
TypeScript
287 lines
10 KiB
TypeScript
import { describe, expect, it } from "bun:test";
|
|
import { loadCases } from "./cases";
|
|
|
|
describe("loadCases", () => {
|
|
it("loads backend preview runtime config for opt-in flow cases", async () => {
|
|
const flowCases = await loadCases("flow");
|
|
const caseEntry = flowCases.find((entry) => entry.id === "flow-test1-reuse-existing-script");
|
|
|
|
expect(caseEntry?.runtime).toEqual({
|
|
backendPreview: {
|
|
args: {
|
|
a: 2,
|
|
b: 3,
|
|
},
|
|
},
|
|
});
|
|
expect(caseEntry?.toolExpect).toEqual({
|
|
requiredToolsUsed: ["test_run_flow"],
|
|
});
|
|
});
|
|
|
|
it("loads script and flow test tool expectations", async () => {
|
|
const scriptCases = await loadCases("script");
|
|
const flowCases = await loadCases("flow");
|
|
|
|
expect(scriptCases.find((entry) => entry.id === "script-test1-greet-user")?.toolExpect).toEqual({
|
|
requiredToolsUsed: ["test_run_script"],
|
|
});
|
|
expect(flowCases.find((entry) => entry.id === "flow-test0-sum-two-numbers")?.toolExpect).toEqual({
|
|
requiredToolsUsed: ["test_run_flow"],
|
|
});
|
|
});
|
|
|
|
it("loads the workspace-flow preference benchmark case", async () => {
|
|
const flowCases = await loadCases("flow");
|
|
const caseEntry = flowCases.find(
|
|
(entry) => entry.id === "flow-test13-prefer-existing-workspace-flow"
|
|
);
|
|
|
|
expect(caseEntry).toBeDefined();
|
|
expect(caseEntry?.runtime).toEqual({
|
|
backendPreview: {
|
|
args: {
|
|
a: 10,
|
|
b: 5,
|
|
},
|
|
},
|
|
});
|
|
expect(caseEntry?.initialPath).toContain(
|
|
"ai_evals/fixtures/frontend/flow/initial/test13_prefer_existing_workspace_flow_initial.json"
|
|
);
|
|
expect(caseEntry?.expectedPath).toContain(
|
|
"ai_evals/fixtures/frontend/flow/expected/test13_prefer_existing_workspace_flow.json"
|
|
);
|
|
});
|
|
|
|
it("loads app validation config for datatable-backed persistence cases", async () => {
|
|
const appCases = await loadCases("app");
|
|
const caseEntry = appCases.find(
|
|
(entry) => entry.id === "app-test8-inventory-tracker-search-delete"
|
|
);
|
|
|
|
expect(caseEntry?.initialPath).toContain("ai_evals/fixtures/frontend/app/initial/inventory_tracker");
|
|
expect(caseEntry?.validate).toEqual({
|
|
requiredFrontendPaths: ["/index.tsx"],
|
|
requiredBackendRunnableKeys: ["listInventory", "addInventory", "deleteInventory"],
|
|
requiredBackendRunnableTypes: [
|
|
{ key: "listInventory", type: "inline" },
|
|
{ key: "addInventory", type: "inline" },
|
|
{ key: "deleteInventory", type: "inline" },
|
|
],
|
|
requiredDatatables: [
|
|
{
|
|
datatableName: "main",
|
|
schema: "public",
|
|
table: "inventory_items",
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it("loads the seeded recipe-book app modification case", async () => {
|
|
const appCases = await loadCases("app");
|
|
const caseEntry = appCases.find((entry) => entry.id === "app-test9-recipe-book-search-delete");
|
|
|
|
expect(caseEntry?.initialPath).toContain("ai_evals/fixtures/frontend/app/initial/recipe_book");
|
|
expect(caseEntry?.validate).toEqual({
|
|
requiredFrontendPaths: ["/index.tsx"],
|
|
requiredBackendRunnableKeys: ["listRecipes", "addRecipe", "deleteRecipe"],
|
|
requiredBackendRunnableTypes: [
|
|
{ key: "listRecipes", type: "inline" },
|
|
{ key: "addRecipe", type: "inline" },
|
|
{ key: "deleteRecipe", type: "inline" },
|
|
],
|
|
requiredDatatables: [
|
|
{
|
|
datatableName: "main",
|
|
schema: "public",
|
|
table: "recipes",
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it("loads the file-manager rename save/cancel case", async () => {
|
|
const appCases = await loadCases("app");
|
|
const caseEntry = appCases.find(
|
|
(entry) => entry.id === "app-test6-file-manager-rename-save-cancel"
|
|
);
|
|
|
|
expect(caseEntry?.initialPath).toContain("ai_evals/fixtures/frontend/app/initial/file_manager");
|
|
expect(caseEntry?.validate).toMatchObject({
|
|
requiredFrontendPaths: ["/index.tsx", "/components/FileItem.tsx"],
|
|
requiredFrontendFileContent: [
|
|
{
|
|
path: "/components/FileItem.tsx",
|
|
includes: ["Save", "Cancel", "Escape"],
|
|
},
|
|
],
|
|
forbiddenAppContent: ["onBlur={handleRename}"],
|
|
});
|
|
});
|
|
|
|
it("loads the datatable-backed notes creation case", async () => {
|
|
const appCases = await loadCases("app");
|
|
const caseEntry = appCases.find((entry) => entry.id === "app-datatable-persistent-notes");
|
|
|
|
expect(caseEntry?.initialPath).toContain("ai_evals/fixtures/frontend/app/initial/notes_datatable");
|
|
expect(caseEntry?.runtime).toEqual({
|
|
maxTurns: 10,
|
|
});
|
|
expect(caseEntry?.validate).toMatchObject({
|
|
requiredFrontendPaths: ["/index.tsx"],
|
|
requiredBackendRunnableKeys: ["listNotes", "addNote", "deleteNote"],
|
|
datatableTableCountExactly: 1,
|
|
requiredDatatables: [
|
|
{
|
|
datatableName: "main",
|
|
schema: "public",
|
|
table: "notes",
|
|
},
|
|
],
|
|
requiredToolsUsed: ["list_datatables", "get_datatable_table_schema"],
|
|
forbiddenAppContent: ["localStorage", "sessionStorage", "indexedDB"],
|
|
});
|
|
});
|
|
|
|
it("loads the session id micro-edit app case", async () => {
|
|
const appCases = await loadCases("app");
|
|
const caseEntry = appCases.find((entry) => entry.id === "app-test10-session-id-no-crypto");
|
|
|
|
expect(caseEntry?.initialPath).toContain("ai_evals/fixtures/frontend/app/initial/session_id_chat");
|
|
expect(caseEntry?.runtime).toEqual({
|
|
maxTurns: 4,
|
|
});
|
|
expect(caseEntry?.validate).toEqual({
|
|
requiredFrontendPaths: ["/index.tsx"],
|
|
requiredBackendRunnableKeys: ["a"],
|
|
requiredBackendRunnableTypes: [{ key: "a", type: "inline" }],
|
|
});
|
|
});
|
|
|
|
it("loads app token usage cases with additional runtime context", async () => {
|
|
const appCases = await loadCases("app");
|
|
const datatableContextCase = appCases.find(
|
|
(entry) => entry.id === "app-token-many-datatable-context"
|
|
);
|
|
|
|
expect(
|
|
appCases.find((entry) => entry.id === "app-token-selected-large-frontend-context")
|
|
).toBeUndefined();
|
|
expect(
|
|
appCases.find((entry) => entry.id === "app-token-selected-large-backend-context")
|
|
).toBeUndefined();
|
|
expect(datatableContextCase?.initialPath).toContain(
|
|
"ai_evals/fixtures/frontend/app/initial/token_heavy_datatables"
|
|
);
|
|
expect(datatableContextCase?.runtime?.appContext?.additional).toHaveLength(10);
|
|
expect(datatableContextCase?.runtime?.appContext?.additional?.[0]).toEqual({
|
|
type: "datatable",
|
|
datatableName: "main",
|
|
schema: "analytics",
|
|
table: "event_log_01",
|
|
});
|
|
});
|
|
|
|
it("loads CLI behavior expectations for deploy-guidance cases", async () => {
|
|
const cliCases = await loadCases("cli");
|
|
const caseEntry = cliCases.find((entry) => entry.id === "bun-hello-script");
|
|
|
|
expect(caseEntry?.cliExpect).toEqual({
|
|
requiredSkills: ["write-script-bun"],
|
|
requiredSkillsBeforeFirstMutation: ["write-script-bun"],
|
|
forbiddenSkills: ["write-script-python3", "write-flow"],
|
|
orderedAssistantMentions: ["wmill generate-metadata", "wmill sync push"],
|
|
orderedProposedCommands: ["wmill generate-metadata", "wmill sync push"],
|
|
forbiddenExecutedCommands: ["^wmill generate-metadata", "^wmill sync push"],
|
|
});
|
|
});
|
|
|
|
it("loads global draft validation and forbidden tool expectations", async () => {
|
|
const globalCases = await loadCases("global");
|
|
const caseEntry = globalCases.find((entry) => entry.id === "global-test1-script-create");
|
|
|
|
expect(caseEntry?.validate).toMatchObject({
|
|
draftCountExactly: 1,
|
|
requiredDrafts: [
|
|
{
|
|
type: "script",
|
|
path: "f/evals/global/greet_user",
|
|
language: "bun",
|
|
},
|
|
],
|
|
});
|
|
expect(caseEntry?.initialPath).toContain(
|
|
"ai_evals/fixtures/frontend/global/initial/user_admin_evals_folder.json"
|
|
);
|
|
expect(caseEntry?.toolExpect).toMatchObject({
|
|
requiredToolsUsed: ["write_script"],
|
|
forbiddenToolsUsed: ["deploy_workspace_item", "delete_workspace_item"],
|
|
});
|
|
});
|
|
|
|
it("loads global active-editor eval cases", async () => {
|
|
const globalCases = await loadCases("global");
|
|
const scriptCase = globalCases.find(
|
|
(entry) => entry.id === "global-test12-current-live-script-edit"
|
|
);
|
|
const flowCase = globalCases.find(
|
|
(entry) => entry.id === "global-test13-current-live-flow-edit"
|
|
);
|
|
|
|
expect(scriptCase?.initialPath).toContain(
|
|
"ai_evals/fixtures/frontend/global/initial/current_greeting_live_script.json"
|
|
);
|
|
expect(scriptCase?.toolExpect).toMatchObject({
|
|
requiredToolsUsed: ["read_workspace_item"],
|
|
});
|
|
expect(flowCase?.initialPath).toContain(
|
|
"ai_evals/fixtures/frontend/global/initial/current_invoice_live_flow.json"
|
|
);
|
|
expect(flowCase?.validate).toMatchObject({
|
|
requiredDrafts: [
|
|
{
|
|
type: "flow",
|
|
path: "f/evals/global/current_invoice_flow",
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it("loads global docs-search cases as tool-use checks", async () => {
|
|
const globalCases = await loadCases("global");
|
|
const docsCases = globalCases.filter((entry) =>
|
|
entry.id.startsWith("global-docs-"),
|
|
);
|
|
expect(docsCases.length).toBeGreaterThanOrEqual(3);
|
|
|
|
// Each docs case verifies the assistant reaches for search_docs and does not
|
|
// draft anything; with no draft, the global judge is skipped.
|
|
for (const entry of docsCases) {
|
|
expect(entry.skipJudge).toBe(true);
|
|
expect(entry.toolExpect?.requiredToolsUsed).toContain("search_docs");
|
|
}
|
|
});
|
|
|
|
it("loads tool expectations for workspace mutation cases", async () => {
|
|
const scriptCases = await loadCases("script");
|
|
const caseEntry = scriptCases.find(
|
|
(entry) => entry.id === "script-test2-create-current-script-schedule"
|
|
);
|
|
|
|
expect(caseEntry?.toolExpect).toEqual({
|
|
requiredToolsUsed: ["test_run_script", "create_schedule"],
|
|
toolCallArgs: [
|
|
{
|
|
tool: "create_schedule",
|
|
field: "path",
|
|
stringStartsWithAnyOf: ["f/", "u/"],
|
|
stringMustNotStartWithAnyOf: ["schedules/"],
|
|
},
|
|
],
|
|
});
|
|
expect(caseEntry?.skipJudge).toBe(true);
|
|
});
|
|
});
|