95 lines
2.9 KiB
JavaScript
95 lines
2.9 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
import ts from "typescript";
|
|
|
|
const testDir = path.dirname(fileURLToPath(import.meta.url));
|
|
const sourcePath = path.resolve(testDir, "../src/features/article-review/model.ts");
|
|
const source = readFileSync(sourcePath, "utf8");
|
|
const compiled = ts.transpileModule(source, {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 },
|
|
});
|
|
|
|
const moduleExports = {};
|
|
new Function("exports", compiled.outputText)(moduleExports);
|
|
|
|
const { buildReviewIssueRows, buildFinalReviewSummary } = moduleExports;
|
|
|
|
const seoReport = {
|
|
id: "11111111-1111-1111-1111-111111111111",
|
|
article_id: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
|
|
review_kind: "SEO",
|
|
draft_id: "dddddddd-dddd-dddd-dddd-dddddddddddd",
|
|
score: 72,
|
|
issues: [
|
|
{
|
|
id: "meta-description-length",
|
|
suggestion_id: "22222222-2222-2222-2222-222222222222",
|
|
severity: "HIGH",
|
|
location: "meta_description",
|
|
message: "Meta description too short.",
|
|
suggested_fix: "Use 120-160 chars.",
|
|
suggested_rewrite: "Expanded meta description text.",
|
|
status: "PENDING",
|
|
},
|
|
],
|
|
recommended_slug: "seo-language-review-guide",
|
|
recommended_title: "SEO Language Review Guide",
|
|
schema_json: { "@type": "Article" },
|
|
rules_snapshot: { meta_description_min: 120 },
|
|
created_at: "2026-05-22T12:00:00Z",
|
|
};
|
|
|
|
const languageReport = {
|
|
...seoReport,
|
|
id: "33333333-3333-3333-3333-333333333333",
|
|
review_kind: "LANGUAGE",
|
|
issues: [
|
|
{
|
|
id: "long-sentence",
|
|
suggestion_id: "44444444-4444-4444-4444-444444444444",
|
|
severity: "MEDIUM",
|
|
location: "body_markdown",
|
|
message: "Sentence exceeds 24 words.",
|
|
suggested_fix: "Split sentence.",
|
|
suggested_rewrite: "This sentence is shorter.",
|
|
status: "ACCEPTED",
|
|
},
|
|
],
|
|
};
|
|
|
|
const rows = buildReviewIssueRows(seoReport, languageReport);
|
|
assert.equal(rows.length, 2);
|
|
assert.equal(rows[0].reviewKind, "SEO");
|
|
assert.equal(rows[0].suggestionId, "22222222-2222-2222-2222-222222222222");
|
|
assert.equal(rows[1].reviewKind, "LANGUAGE");
|
|
assert.equal(rows[1].status, "ACCEPTED");
|
|
|
|
const summary = buildFinalReviewSummary({
|
|
article_id: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
|
|
unresolved_count: 2,
|
|
unresolved_issues: [
|
|
{
|
|
review_kind: "SEO",
|
|
suggestion_id: "22222222-2222-2222-2222-222222222222",
|
|
severity: "HIGH",
|
|
location: "meta_description",
|
|
message: "Meta description too short.",
|
|
status: "PENDING",
|
|
},
|
|
{
|
|
review_kind: "LANGUAGE",
|
|
suggestion_id: "55555555-5555-5555-5555-555555555555",
|
|
severity: "MEDIUM",
|
|
location: "body_markdown",
|
|
message: "Sentence exceeds 24 words.",
|
|
status: "PENDING",
|
|
},
|
|
],
|
|
});
|
|
assert.equal(summary.unresolvedCount, 2);
|
|
assert.equal(summary.unresolvedTitles.length, 2);
|
|
assert.ok(summary.unresolvedTitles[0].startsWith("SEO:"));
|