Download src/utils/automation-export.test.ts from SaylorTwift/openhands: direct link, hf CLI and curl.
- Browser
- Download file 4.22 kB
-
https://huggingface.co/SaylorTwift/openhands/resolve/main/src/utils/automation-export.test.ts
- Command line
-
hf download hf://SaylorTwift/openhands/src/utils/automation-export.test.ts
-
curl -L -o automation-export.test.ts https://huggingface.co/SaylorTwift/openhands/resolve/main/src/utils/automation-export.test.ts
4.22 kB
| import { describe, expect, it } from "vitest"; | |
| import type { Automation } from "#/types/automation"; | |
| import { | |
| AutomationFileValidationError, | |
| parseAutomationFile, | |
| serializeAutomation, | |
| } from "./automation-export"; | |
| const cronAutomation: Automation = { | |
| id: "automation-1", | |
| name: "Daily review", | |
| trigger: { | |
| type: "cron", | |
| schedule: "0 9 * * *", | |
| schedule_human: "Daily at 09:00", | |
| }, | |
| enabled: true, | |
| repository: "openhands/agent-canvas", | |
| branch: "main", | |
| model: "fast", | |
| prompt: "Review open pull requests.", | |
| plugins: ["github:openhands/extensions"], | |
| notification: "Post a summary", | |
| timezone: "America/Los_Angeles", | |
| created_at: "2026-07-01T00:00:00Z", | |
| updated_at: "2026-07-02T00:00:00Z", | |
| last_triggered_at: "2026-07-03T00:00:00Z", | |
| }; | |
| describe("automation export files", () => { | |
| it("round-trips a cron automation without server-assigned fields", () => { | |
| const exported = serializeAutomation(cronAutomation); | |
| expect(exported).toEqual({ | |
| version: 1, | |
| kind: "automation", | |
| spec: { | |
| name: cronAutomation.name, | |
| trigger: cronAutomation.trigger, | |
| enabled: true, | |
| repository: cronAutomation.repository, | |
| model: cronAutomation.model, | |
| prompt: cronAutomation.prompt, | |
| branch: cronAutomation.branch, | |
| plugins: cronAutomation.plugins, | |
| notification: cronAutomation.notification, | |
| timezone: cronAutomation.timezone, | |
| }, | |
| }); | |
| expect(parseAutomationFile(exported)).toEqual(exported.spec); | |
| expect(exported.spec).not.toHaveProperty("id"); | |
| expect(exported.spec).not.toHaveProperty("created_at"); | |
| expect(exported.spec).not.toHaveProperty("updated_at"); | |
| expect(exported.spec).not.toHaveProperty("last_triggered_at"); | |
| }); | |
| it("round-trips event trigger fields", () => { | |
| const exported = serializeAutomation({ | |
| ...cronAutomation, | |
| trigger: { | |
| type: "event", | |
| source: "github", | |
| on: ["pull_request.opened", "pull_request.synchronize"], | |
| filter: "repository.full_name == 'openhands/agent-canvas'", | |
| }, | |
| timezone: undefined, | |
| }); | |
| expect(parseAutomationFile(exported).trigger).toEqual( | |
| exported.spec.trigger, | |
| ); | |
| }); | |
| it("preserves a positive timeout through an export/import round-trip", () => { | |
| const withTimeout: Automation = { ...cronAutomation, timeout: 900 }; | |
| const exported = serializeAutomation(withTimeout); | |
| expect(parseAutomationFile(exported).timeout).toBe(900); | |
| }); | |
| it("reports every malformed field with its path", () => { | |
| const malformed = { | |
| version: 2, | |
| kind: "workflow", | |
| spec: { | |
| name: "", | |
| prompt: null, | |
| enabled: "yes", | |
| trigger: { type: "event", source: 42, on: [] }, | |
| plugins: ["github:openhands/extensions", 42], | |
| model: false, | |
| timeout: -5, | |
| }, | |
| }; | |
| expect(() => parseAutomationFile(malformed)).toThrow( | |
| AutomationFileValidationError, | |
| ); | |
| try { | |
| parseAutomationFile(malformed); | |
| } catch (error) { | |
| expect(error).toBeInstanceOf(AutomationFileValidationError); | |
| expect((error as AutomationFileValidationError).issues).toEqual( | |
| expect.arrayContaining([ | |
| "version: expected 1", | |
| 'kind: expected "automation"', | |
| "spec.name: expected a non-empty string", | |
| "spec.prompt: expected a non-empty string", | |
| "spec.enabled: expected a boolean", | |
| "spec.trigger.source: expected a string", | |
| "spec.trigger.source: required for an event trigger", | |
| "spec.trigger.on: expected a string or a non-empty array of strings", | |
| "spec.trigger.on: required for an event trigger", | |
| "spec.plugins: expected an array of non-empty strings", | |
| "spec.model: expected a non-empty string or null", | |
| "spec.timeout: expected a positive integer", | |
| ]), | |
| ); | |
| } | |
| }); | |
| it("rejects non-object files and missing specs", () => { | |
| expect(() => parseAutomationFile(null)).toThrow( | |
| "file: expected a JSON object", | |
| ); | |
| expect(() => | |
| parseAutomationFile({ version: 1, kind: "automation" }), | |
| ).toThrow("spec: expected an object"); | |
| }); | |
| }); | |