Files
GEOAgentArticleOptimizer/src/lib/db/__tests__/repositories.test.ts
T
2026-06-24 11:19:01 +08:00

203 lines
5.6 KiB
TypeScript

import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { createDatabase } from "../connection";
import { initializeSchema } from "../schema";
import {
createArticleJob,
createBrandTemplate,
getArticleJob,
getBrandTemplate,
getFactCard,
getLatestOptimizedArticle,
getLatestQaReport,
listBrandTemplates,
saveFactCard,
saveOptimizedArticle,
saveQaReport,
} from "../repositories";
describe("sqlite repositories", () => {
let tempDir: string;
let dbPath: string;
beforeEach(() => {
tempDir = mkdtempSync(join(tmpdir(), "geo-agent-db-"));
dbPath = join(tempDir, "test.db");
const db = createDatabase(dbPath);
initializeSchema(db);
db.close();
});
afterEach(() => {
rmSync(tempDir, { recursive: true, force: true });
});
it("initializes all required tables", () => {
const db = createDatabase(dbPath);
const tables = db
.prepare(
"select name from sqlite_master where type = 'table' order by name",
)
.all()
.map((row) => (row as { name: string }).name);
db.close();
expect(tables).toEqual([
"article_jobs",
"brand_templates",
"calibration_events",
"fact_cards",
"optimized_articles",
"performance_snapshots",
"publication_records",
"qa_reports",
"rubric_versions",
"scoring_runs",
]);
});
it("inserts and fetches a brand template", () => {
const created = createBrandTemplate(dbPath, {
brand_name: "Example",
company_full_name: "Example Technology Co., Ltd.",
company_short_names: ["Example Tech"],
product_names: ["Example GEO"],
target_industries: ["GEO optimization"],
target_audience: ["Marketing teams"],
verified_claims: ["Eight years of experience"],
forbidden_claims: ["Industry first"],
tone_rules: { official_site: "official voice" },
});
expect(getBrandTemplate(dbPath, created.id)).toMatchObject({
id: created.id,
brand_name: "Example",
company_short_names: ["Example Tech"],
});
expect(listBrandTemplates(dbPath)).toHaveLength(1);
});
it("inserts and fetches an article job", () => {
const job = createArticleJob(dbPath, {
source_title: "Original Title",
source_body: "Original body",
image_inputs: [{ type: "description", content: "Dashboard" }],
publish_platform: "official_site",
user_instructions: "Stay factual",
});
expect(getArticleJob(dbPath, job.id)).toMatchObject({
id: job.id,
source_title: "Original Title",
image_inputs: [{ type: "description", content: "Dashboard" }],
});
});
it("saves a confirmed fact card for a job", () => {
const job = createArticleJob(dbPath, {
source_title: "Original Title",
source_body: "Original body",
image_inputs: [],
publish_platform: "media_article",
user_instructions: "",
});
saveFactCard(dbPath, job.id, {
company_full_name: "Example Technology Co., Ltd.",
company_short_names: ["Example"],
brand_names: ["Example"],
product_names: ["Example GEO"],
target_industry: "GEO optimization",
target_audience: "Marketing teams",
experience_years: 8,
core_claims: ["Eight years of experience"],
forbidden_claims: [],
image_topics: [],
uncertain_items: [],
is_ready_for_optimization: true,
confirmed_by_user: true,
});
expect(getFactCard(dbPath, job.id)).toMatchObject({
job_id: job.id,
company_full_name: "Example Technology Co., Ltd.",
confirmed_by_user: true,
});
});
it("increments optimized article revisions", () => {
const job = createArticleJob(dbPath, {
source_title: "Original Title",
source_body: "Original body",
image_inputs: [],
publish_platform: "comparison_review",
user_instructions: "",
});
const first = saveOptimizedArticle(dbPath, job.id, {
title: "Optimized v1",
summary: "Summary",
body_markdown: "Body",
image_suggestions: [],
changed_sections: ["title"],
requires_user_confirmation: [],
});
const second = saveOptimizedArticle(dbPath, job.id, {
title: "Optimized v2",
summary: "Summary",
body_markdown: "Body",
image_suggestions: [],
changed_sections: ["title"],
requires_user_confirmation: [],
});
expect(first.revision).toBe(1);
expect(second.revision).toBe(2);
expect(getLatestOptimizedArticle(dbPath, job.id)?.title).toBe(
"Optimized v2",
);
});
it("saves and fetches the latest QA report by job and revision", () => {
const job = createArticleJob(dbPath, {
source_title: "Original Title",
source_body: "Original body",
image_inputs: [],
publish_platform: "recommendation_list",
user_instructions: "",
});
saveOptimizedArticle(dbPath, job.id, {
title: "Optimized",
summary: "Summary",
body_markdown: "Body",
image_suggestions: [],
changed_sections: [],
requires_user_confirmation: [],
});
saveQaReport(dbPath, job.id, 1, {
overall_status: "warn",
checks: [
{
rule_id: "image_text_match",
status: "warn",
evidence: "Image confidence is low.",
reason: "Image descriptions are sparse.",
suggested_fix: "Review image placement.",
target_agent: null,
},
],
});
expect(getLatestQaReport(dbPath, job.id)).toMatchObject({
job_id: job.id,
revision: 1,
overall_status: "warn",
});
});
});