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/minimax.test.ts
1import assert from "node:assert/strict";2import fs from "node:fs/promises";3import os from "node:os";4import path from "node:path";5import test, { type TestContext } from "node:test";67import type { CliArgs } from "../types.ts";8import {9buildMinimaxUrl,10buildRequestBody,11buildSubjectReference,12extractImageFromResponse,13parsePixelSize,14validateArgs,15} from "./minimax.ts";1617function useEnv(18t: TestContext,19values: Record<string, string | null>,20): void {21const previous = new Map<string, string | undefined>();22for (const [key, value] of Object.entries(values)) {23previous.set(key, process.env[key]);24if (value == null) {25delete process.env[key];26} else {27process.env[key] = value;28}29}3031t.after(() => {32for (const [key, value] of previous.entries()) {33if (value == null) {34delete process.env[key];35} else {36process.env[key] = value;37}38}39});40}4142function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {43return {44prompt: null,45promptFiles: [],46imagePath: null,47provider: null,48model: null,49aspectRatio: null,50size: null,51quality: null,52imageSize: null,53referenceImages: [],54n: 1,55batchFile: null,56jobs: null,57json: false,58help: false,59...overrides,60};61}6263test("MiniMax URL builder uses documented default and normalizes /v1 suffixes", (t) => {64useEnv(t, { MINIMAX_BASE_URL: null });65assert.equal(buildMinimaxUrl(), "https://api.minimaxi.com/v1/image_generation");6667process.env.MINIMAX_BASE_URL = "https://api.minimax.io";68assert.equal(buildMinimaxUrl(), "https://api.minimax.io/v1/image_generation");6970process.env.MINIMAX_BASE_URL = "https://proxy.example.com/custom/v1/";71assert.equal(buildMinimaxUrl(), "https://proxy.example.com/custom/v1/image_generation");72});7374test("MiniMax size parsing and validation follow documented constraints", () => {75assert.deepEqual(parsePixelSize("1536x1024"), { width: 1536, height: 1024 });76assert.deepEqual(parsePixelSize("1536*1024"), { width: 1536, height: 1024 });77assert.equal(parsePixelSize("wide"), null);7879validateArgs("image-01", makeArgs({ size: "1536x1024", n: 9 }));8081assert.throws(82() => validateArgs("image-01-live", makeArgs({ size: "1536x1024" })),83/only supported with model image-01/,84);85assert.throws(86() => validateArgs("image-01", makeArgs({ size: "1537x1024" })),87/divisible by 8/,88);89assert.throws(90() => validateArgs("image-01", makeArgs({ aspectRatio: "2.35:1" })),91/aspect_ratio must be one of/,92);93assert.throws(94() => validateArgs("image-01", makeArgs({ n: 10 })),95/at most 9 images/,96);97});9899test("MiniMax request body maps aspect ratio, size, n, and subject references", async (t) => {100const dir = await fs.mkdtemp(path.join(os.tmpdir(), "minimax-test-"));101t.after(() => fs.rm(dir, { recursive: true, force: true }));102103const refPath = path.join(dir, "portrait.png");104await fs.writeFile(refPath, Buffer.from("portrait"));105106const ratioBody = await buildRequestBody(107"A portrait by the window",108"image-01",109makeArgs({ aspectRatio: "16:9", n: 2, referenceImages: [refPath] }),110);111assert.equal(ratioBody.aspect_ratio, "16:9");112assert.equal(ratioBody.n, 2);113assert.equal(ratioBody.response_format, "base64");114assert.match(ratioBody.subject_reference?.[0]?.image_file || "", /^data:image\/png;base64,/);115116const sizeBody = await buildRequestBody(117"A portrait by the window",118"image-01",119makeArgs({ size: "1536x1024" }),120);121assert.equal(sizeBody.width, 1536);122assert.equal(sizeBody.height, 1024);123assert.equal(sizeBody.aspect_ratio, undefined);124});125126test("MiniMax subject references require supported file types", async (t) => {127const dir = await fs.mkdtemp(path.join(os.tmpdir(), "minimax-ref-"));128t.after(() => fs.rm(dir, { recursive: true, force: true }));129130const good = path.join(dir, "portrait.jpg");131const bad = path.join(dir, "portrait.webp");132await fs.writeFile(good, Buffer.from("portrait"));133await fs.writeFile(bad, Buffer.from("portrait"));134135const subjectReference = await buildSubjectReference([good]);136assert.equal(subjectReference?.[0]?.type, "character");137138await assert.rejects(139() => buildSubjectReference([bad]),140/only supports JPG, JPEG, or PNG/,141);142});143144test("MiniMax response extraction supports base64 and URL payloads", async (t) => {145const originalFetch = globalThis.fetch;146t.after(() => {147globalThis.fetch = originalFetch;148});149150const fromBase64 = await extractImageFromResponse({151data: {152image_base64: [Buffer.from("hello").toString("base64")],153},154});155assert.equal(Buffer.from(fromBase64).toString("utf8"), "hello");156157globalThis.fetch = async () =>158new Response(Uint8Array.from([1, 2, 3]), {159status: 200,160headers: { "Content-Type": "image/jpeg" },161});162163const fromUrl = await extractImageFromResponse({164data: {165image_urls: ["https://example.com/output.jpg"],166},167});168assert.deepEqual([...fromUrl], [1, 2, 3]);169170await assert.rejects(171() => extractImageFromResponse({ base_resp: { status_code: 1001, status_msg: "blocked" } }),172/blocked/,173);174});175