Files
wehub-resource-sync adf0d17497
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:17:32 +08:00

229 lines
7.2 KiB
TypeScript

import { describe, test, expect } from "vitest";
import {
canonicalizePort,
extract_choices,
normalizeOperatorPorts,
normalize_space_id
} from "./space-api";
import { MODALITIES } from "./workflow-modalities";
import type { Port } from "./workflow-types";
const imageModality = MODALITIES.find((m) => m.key === "image")!;
const audioModality = MODALITIES.find((m) => m.key === "audio")!;
const textModality = MODALITIES.find((m) => m.key === "text")!;
describe("canonicalizePort", () => {
test("passes through already-specific types regardless of hint", () => {
expect(canonicalizePort("text", "image")).toBe("text");
expect(canonicalizePort("audio")).toBe("audio");
expect(canonicalizePort("image", "image")).toBe("image");
});
test("falls back unchanged when no hint is supplied", () => {
expect(canonicalizePort("any")).toBe("any");
expect(canonicalizePort("file")).toBe("file");
});
test("clamps `any` to the modality canonical type derived from a hint", () => {
expect(canonicalizePort("any", "image")).toBe("image");
expect(canonicalizePort("any", "audio")).toBe("audio");
expect(canonicalizePort("any", "model3d")).toBe("model3d");
});
test("clamps `file` similarly", () => {
expect(canonicalizePort("file", "video")).toBe("video");
expect(canonicalizePort("file", "text")).toBe("text");
});
test("leaves fallback unchanged when the hint has no picker modality", () => {
expect(canonicalizePort("any", "number")).toBe("any");
expect(canonicalizePort("file", "boolean")).toBe("file");
expect(canonicalizePort("any", "json")).toBe("any");
});
});
describe("normalizeOperatorPorts", () => {
test("returns the same ports when modality is null", () => {
const ports: Port[] = [{ id: "in", label: "Input", type: "any" }];
expect(normalizeOperatorPorts(null, ports)).toEqual(ports);
});
test("returns the same ports when modality has no canonical port_type", () => {
const dataset = MODALITIES.find((m) => m.key === "image")!;
// data / model modalities have port_type: null — simulate with a stub
const noopModality = { ...dataset, port_type: null };
const ports: Port[] = [{ id: "in", label: "Input", type: "any" }];
expect(normalizeOperatorPorts(noopModality, ports)).toEqual(ports);
});
test("clamps `any` and `file` to the modality canonical type", () => {
const ports: Port[] = [
{ id: "in", label: "Input A", type: "any" },
{ id: "out", label: "Output", type: "file" }
];
const result = normalizeOperatorPorts(imageModality, ports);
expect(result[0].type).toBe("image");
expect(result[1].type).toBe("image");
});
test("does not touch already-specific ports", () => {
const ports: Port[] = [
{ id: "in", label: "Prompt", type: "text" },
{ id: "out", label: "Image", type: "image" }
];
const result = normalizeOperatorPorts(audioModality, ports);
expect(result[0].type).toBe("text");
expect(result[1].type).toBe("image");
});
test("preserves other port fields (id, label, required, default_value)", () => {
const ports: Port[] = [
{
id: "in_0",
label: "Prompt",
type: "any",
required: true,
default_value: "hello"
}
];
const [out] = normalizeOperatorPorts(textModality, ports);
expect(out.id).toBe("in_0");
expect(out.label).toBe("Prompt");
expect(out.required).toBe(true);
expect(out.default_value).toBe("hello");
expect(out.type).toBe("text");
});
test("returns a new array (does not mutate input)", () => {
const ports: Port[] = [{ id: "in", label: "x", type: "any" }];
const result = normalizeOperatorPorts(imageModality, ports);
expect(result).not.toBe(ports);
expect(ports[0].type).toBe("any");
});
});
describe("normalize_space_id", () => {
test("passes through bare owner/repo", () => {
expect(normalize_space_id("owner/repo")).toBe("owner/repo");
});
test("accepts owner/repo with hyphens, dots, underscores", () => {
expect(normalize_space_id("JacobLinCool/audio-super-resolution")).toBe(
"JacobLinCool/audio-super-resolution"
);
expect(normalize_space_id("gradio_app/v1.2-test")).toBe(
"gradio_app/v1.2-test"
);
});
test("parses huggingface.co/spaces/ URLs", () => {
expect(normalize_space_id("https://huggingface.co/spaces/owner/repo")).toBe(
"owner/repo"
);
});
test("parses URLs with trailing paths", () => {
expect(
normalize_space_id(
"https://huggingface.co/spaces/owner/repo/discussions/3"
)
).toBe("owner/repo");
});
test("parses URLs with www subdomain", () => {
expect(
normalize_space_id("https://www.huggingface.co/spaces/owner/repo")
).toBe("owner/repo");
});
test("parses *.hf.space subdomains", () => {
expect(normalize_space_id("https://owner-repo.hf.space")).toBe(
"owner/repo"
);
});
test("hf.space subdomain with multi-hyphen repo names", () => {
// Heuristic: first hyphen splits owner/repo. Imperfect but matches HF's actual subdomain format.
expect(normalize_space_id("https://owner-some-repo-name.hf.space")).toBe(
"owner/some-repo-name"
);
});
test("trims trailing slashes", () => {
expect(
normalize_space_id("https://huggingface.co/spaces/owner/repo/")
).toBe("owner/repo");
expect(normalize_space_id("owner/repo/")).toBe("owner/repo");
});
test("trims whitespace", () => {
expect(normalize_space_id(" owner/repo ")).toBe("owner/repo");
});
test("returns null for empty input", () => {
expect(normalize_space_id("")).toBeNull();
expect(normalize_space_id(" ")).toBeNull();
});
test("returns null for unrecognisable input", () => {
expect(normalize_space_id("just-a-name")).toBeNull();
expect(normalize_space_id("https://example.com/foo")).toBeNull();
});
test("returns null for too-many-slashes plain input", () => {
// A plain "a/b/c" isn't an HF Space ID (HF Spaces are owner/repo only).
expect(normalize_space_id("a/b/c")).toBeNull();
});
});
describe("extract_choices", () => {
test("pulls single-select enum from a Dropdown / Radio schema", () => {
expect(extract_choices({ type: "string", enum: ["a", "b", "c"] })).toEqual({
choices: ["a", "b", "c"],
multiselect: false
});
});
test("pulls multiselect enum from a CheckboxGroup schema", () => {
expect(
extract_choices({
type: "array",
items: { type: "string", enum: ["x", "y"] }
})
).toEqual({ choices: ["x", "y"], multiselect: true });
});
test("coerces non-string enum values to strings", () => {
expect(extract_choices({ type: "number", enum: [1, 2, 3] })).toEqual({
choices: ["1", "2", "3"],
multiselect: false
});
});
test("returns null for a plain string schema (no enum)", () => {
expect(extract_choices({ type: "string" })).toBeNull();
});
test("returns null for an array schema whose items lack enum", () => {
expect(
extract_choices({ type: "array", items: { type: "string" } })
).toBeNull();
});
test("returns null for an empty enum array", () => {
expect(extract_choices({ type: "string", enum: [] })).toBeNull();
});
test("returns null for an array schema with empty items.enum", () => {
expect(
extract_choices({ type: "array", items: { type: "string", enum: [] } })
).toBeNull();
});
test("returns null for missing / non-object inputs", () => {
expect(extract_choices(undefined)).toBeNull();
expect(extract_choices(null)).toBeNull();
expect(extract_choices("string")).toBeNull();
});
});