Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Generate images via OpenAI, Google, OpenRouter, DashScope, Jimeng, Seedream, and Replicate APIs with batch support.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/providers/zai.test.ts
1import assert from "node:assert/strict";2import test, { type TestContext } from "node:test";34import type { CliArgs } from "../types.ts";5import {6buildRequestBody,7buildZaiUrl,8extractImageFromResponse,9getDefaultModel,10getModelFamily,11parseAspectRatio,12parseSize,13resolveSizeForModel,14validateArgs,15} from "./zai.ts";1617function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {18return {19prompt: null,20promptFiles: [],21imagePath: null,22provider: null,23model: null,24aspectRatio: null,25size: null,26quality: null,27imageSize: null,28imageApiDialect: null,29referenceImages: [],30n: 1,31batchFile: null,32jobs: null,33json: false,34help: false,35...overrides,36};37}3839function useEnv(40t: TestContext,41values: Record<string, string | null>,42): void {43const previous = new Map<string, string | undefined>();44for (const [key, value] of Object.entries(values)) {45previous.set(key, process.env[key]);46if (value == null) {47delete process.env[key];48} else {49process.env[key] = value;50}51}5253t.after(() => {54for (const [key, value] of previous.entries()) {55if (value == null) {56delete process.env[key];57} else {58process.env[key] = value;59}60}61});62}6364test("Z.AI default model prefers env override and otherwise uses glm-image", (t) => {65useEnv(t, {66ZAI_IMAGE_MODEL: null,67BIGMODEL_IMAGE_MODEL: null,68});69assert.equal(getDefaultModel(), "glm-image");7071process.env.BIGMODEL_IMAGE_MODEL = "cogview-4-250304";72assert.equal(getDefaultModel(), "cogview-4-250304");73});7475test("Z.AI URL builder normalizes host, v4 base, and full endpoint inputs", (t) => {76useEnv(t, { ZAI_BASE_URL: "https://api.z.ai" });77assert.equal(buildZaiUrl(), "https://api.z.ai/api/paas/v4/images/generations");7879process.env.ZAI_BASE_URL = "https://proxy.example.com/api/paas/v4/";80assert.equal(buildZaiUrl(), "https://proxy.example.com/api/paas/v4/images/generations");8182process.env.ZAI_BASE_URL = "https://proxy.example.com/custom/images/generations";83assert.equal(buildZaiUrl(), "https://proxy.example.com/custom/images/generations");84});8586test("Z.AI model family and parsing helpers recognize documented formats", () => {87assert.equal(getModelFamily("glm-image"), "glm");88assert.equal(getModelFamily("cogview-4-250304"), "legacy");89assert.deepEqual(parseAspectRatio("16:9"), { width: 16, height: 9 });90assert.equal(parseAspectRatio("wide"), null);91assert.deepEqual(parseSize("1280x1280"), { width: 1280, height: 1280 });92assert.deepEqual(parseSize("1472*1088"), { width: 1472, height: 1088 });93assert.equal(parseSize("big"), null);94});9596test("Z.AI size resolution follows documented recommended ratios and validates custom sizes", () => {97assert.equal(98resolveSizeForModel("glm-image", makeArgs({ aspectRatio: "16:9", quality: "2k" })),99"1728x960",100);101assert.equal(102resolveSizeForModel("cogview-4-250304", makeArgs({ aspectRatio: "4:3", quality: "normal" })),103"1152x864",104);105assert.equal(106resolveSizeForModel("glm-image", makeArgs({ size: "1568x1056", quality: "2k" })),107"1568x1056",108);109110const uncommon = resolveSizeForModel(111"glm-image",112makeArgs({ aspectRatio: "5:2", quality: "normal" }),113);114const parsed = parseSize(uncommon);115assert.ok(parsed);116assert.ok(parsed.width % 32 === 0);117assert.ok(parsed.height % 32 === 0);118assert.ok(parsed.width * parsed.height <= 2 ** 22);119120assert.throws(121() => resolveSizeForModel("glm-image", makeArgs({ size: "1000x1000", quality: "2k" })),122/between 1024 and 2048/,123);124assert.throws(125() => resolveSizeForModel("glm-image", makeArgs({ size: "1280x1260", quality: "2k" })),126/divisible by 32/,127);128assert.throws(129() => resolveSizeForModel("cogview-4-250304", makeArgs({ size: "2048x2048", quality: "2k" })),130/must not exceed 2\^21 total pixels/,131);132});133134test("Z.AI validation rejects unsupported refs and multi-image requests", () => {135assert.throws(136() => validateArgs("glm-image", makeArgs({ referenceImages: ["ref.png"] })),137/text-to-image only/,138);139assert.throws(140() => validateArgs("glm-image", makeArgs({ n: 2 })),141/single image per request/,142);143});144145test("Z.AI request body maps skill quality and resolved size into provider fields", () => {146const body = buildRequestBody(147"A cinematic science poster",148"glm-image",149makeArgs({ aspectRatio: "4:3", quality: "normal" }),150);151152assert.deepEqual(body, {153model: "glm-image",154prompt: "A cinematic science poster",155quality: "standard",156size: "1472x1088",157});158});159160test("Z.AI response extraction downloads the returned image URL", async (t) => {161const originalFetch = globalThis.fetch;162t.after(() => {163globalThis.fetch = originalFetch;164});165166globalThis.fetch = async () =>167new Response(Uint8Array.from([1, 2, 3]), {168status: 200,169headers: { "Content-Type": "image/png" },170});171172const image = await extractImageFromResponse({173data: [{ url: "https://cdn.example.com/glm-image.png" }],174});175assert.deepEqual([...image], [1, 2, 3]);176177await assert.rejects(178() => extractImageFromResponse({ data: [{}] }),179/No image URL/,180);181});182