// supabase/functions/ai-structured/ai_structured.test.ts
///
///
///
import { assert, assertEquals } from "jsr:@std/assert@1";
import "jsr:@std/dotenv/load";
import { createClient, type SupabaseClient } from "npm:@supabase/supabase-js@2";
const SUPABASE_URL = Deno.env.get("SUPABASE_URL") ?? "";
const SUPABASE_ANON_KEY = Deno.env.get("SUPABASE_ANON_KEY") ?? ""; // (o PUBLISHABLE_KEY si así lo nombraste)
const EMAIL = Deno.env.get("TEST_EMAIL") ?? "guillermo.arrieta@lasalle.mx";
const PASSWORD = Deno.env.get("TEST_PASSWORD") ?? "admin";
const options = {
auth: {
autoRefreshToken: false,
persistSession: false,
detectSessionInUrl: false,
},
};
function mustEnv() {
if (!SUPABASE_URL) throw new Error("SUPABASE_URL is required");
if (!SUPABASE_ANON_KEY) throw new Error("SUPABASE_ANON_KEY is required");
}
async function getAuthedClient(): Promise<
{ client: SupabaseClient; accessToken: string }
> {
mustEnv();
const client = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, options);
const { data, error } = await client.auth.signInWithPassword({
email: EMAIL,
password: PASSWORD,
});
if (error) throw new Error("Sign-in failed: " + error.message);
const accessToken = data.session?.access_token;
if (!accessToken) {
throw new Error("No access_token returned from signInWithPassword");
}
return { client, accessToken };
}
Deno.test("ai-structured (JSON body)", async () => {
const { client, accessToken } = await getAuthedClient();
const form = new FormData();
form.append(
"options",
JSON.stringify({
input: "Genera 3 ideas de negocio innovadoras en formato JSON.",
model: "gpt-5-nano",
text: {
format: {
"type": "json_schema",
"name": "business_ideas",
"schema": {
"type": "array",
"properties": {
"idea": { "type": "string", "description": "The business idea" },
},
"required": ["idea"],
"additionalProperties": false,
},
},
},
}),
);
const { data, error } = await client.functions.invoke("ai-structured", {
headers: {
Authorization: `Bearer ${accessToken}`, // 👈 clave para que tu función pase el authHeader check
},
body: form,
});
if (error) throw new Error("Invoke failed: " + error.message);
assert(data, "Expected data from function");
assertEquals(data.ok, true);
assert(
Array.isArray(data.openai_raw.output),
"Expected output to be an array",
);
assert(data.openai_raw.output.length === 3, "Expected 3 business ideas");
console.log(data);
});
Deno.test("ai-structured (multipart + file)", async () => {
const { client, accessToken } = await getAuthedClient();
// Lee un PDF local (ajusta path)
const bytes = await Deno.readFile("files/carta.pdf");
const file = new File([bytes], "carta.pdf", { type: "application/pdf" });
const payload = {
response: {
input: "Resume estos documentos en JSON.",
model: "gpt-5-nano",
},
structured: {
type: "json_schema",
name: "resumen",
strict: true,
schema: {
type: "object",
properties: { resumen: { type: "string" } },
required: ["resumen"],
additionalProperties: false,
},
},
storage: { prefix: "tmp" },
};
const fd = new FormData();
fd.append("payload", JSON.stringify(payload));
fd.append("files", file);
const { data, error } = await client.functions.invoke("ai-structured", {
headers: {
Authorization: `Bearer ${accessToken}`, // 👈 necesario
// NO pongas Content-Type: fetch lo setea con boundary para FormData ✅
},
method: "POST",
body: fd,
});
if (error) throw new Error("Invoke failed: " + error.message);
assert(data, "Expected data from function");
assertEquals(data.ok, true);
assert(typeof data.output?.resumen === "string");
assert(data.output.resumen.length > 0);
// opcional: valida que registró upload(s) a storage
assert(Array.isArray(data.references?.uploadedToStorage));
});