274 lines
8.0 KiB
JavaScript
274 lines
8.0 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import { resolve } from "node:path";
|
|
|
|
const source = await readFile(resolve("src/utils/longTextCard.js"), "utf8");
|
|
const moduleUrl = `data:text/javascript;base64,${Buffer.from(source).toString("base64")}`;
|
|
const longTextCard = await import(moduleUrl);
|
|
|
|
assert.doesNotMatch(
|
|
source,
|
|
/normalizeLongText/,
|
|
"longTextCard should not contain field-specific normalize helpers"
|
|
);
|
|
|
|
assert.doesNotMatch(
|
|
source,
|
|
/spot_longitude|spot_latitude|spot_tag/,
|
|
"longTextCard should not know spot_locate child field names"
|
|
);
|
|
|
|
const {
|
|
LONG_TEXT_FIELD_CONFIG,
|
|
LONG_TEXT_KEYS,
|
|
appendLongTextChunk,
|
|
createLongTextData,
|
|
getLongTextParsedValue,
|
|
getLongTextSections,
|
|
getLongTextValue,
|
|
hasLongTextExtraSections,
|
|
parseLongTextDisplayValue,
|
|
sanitizeLongTextDisplayValue,
|
|
hasLongTextDisplayValue,
|
|
formatLongTextDisplayValue,
|
|
} = longTextCard;
|
|
|
|
assert.equal(
|
|
source.includes("REMOVED_LONG_TEXT_FIELD_KEYS"),
|
|
false,
|
|
"longTextCard should not carry a removed field blacklist"
|
|
);
|
|
|
|
assert.equal(
|
|
source.includes("hasLongTextChunkPayload"),
|
|
false,
|
|
"ChatMainList should not ask longTextCard to inspect plain data.content payloads"
|
|
);
|
|
|
|
assert.deepEqual(
|
|
parseLongTextDisplayValue('[ "see bridge", "hear water" ]'),
|
|
["see bridge", "hear water"],
|
|
"serialized arrays should be parsed for display"
|
|
);
|
|
|
|
assert.deepEqual(
|
|
parseLongTextDisplayValue('{"spot_name":"bridge","spot_longitude":107.712345}'),
|
|
{ spot_name: "bridge", spot_longitude: 107.712345 },
|
|
"serialized objects should be parsed for display"
|
|
);
|
|
|
|
assert.deepEqual(
|
|
sanitizeLongTextDisplayValue(
|
|
{
|
|
preparation_section: {
|
|
preparation_section_title: "keep",
|
|
preparation_section_items: '[ "check piers", "count arches" ]',
|
|
},
|
|
nested: {
|
|
title: "keep",
|
|
},
|
|
},
|
|
[]
|
|
),
|
|
{
|
|
preparation_section: {
|
|
preparation_section_title: "keep",
|
|
preparation_section_items: ["check piers", "count arches"],
|
|
},
|
|
nested: {
|
|
title: "keep",
|
|
},
|
|
},
|
|
"sanitizing should parse JSON-like strings and ignore configured keys"
|
|
);
|
|
|
|
assert.equal(hasLongTextDisplayValue('["follow up"]'), true);
|
|
assert.equal(hasLongTextDisplayValue({ a: "", b: [" ", null] }), false);
|
|
assert.equal(formatLongTextDisplayValue(true), "\u662f");
|
|
assert.equal(formatLongTextDisplayValue({ title: "bridge" }), '{"title":"bridge"}');
|
|
|
|
const expectedNewKeys = {
|
|
tag: "tag",
|
|
title: "title",
|
|
contentSummary: "content_summary",
|
|
sceneImage: "scene_image",
|
|
preparationSection: "preparation_section",
|
|
sectionSuggestion: "section_suggestion",
|
|
pitfallSection: "pitfall_section",
|
|
commodityList: "commodity_list",
|
|
contentImage: "content_image",
|
|
viewSection: "view_section",
|
|
suggestionSection: "suggestion_section",
|
|
lightReminder: "light_reminder",
|
|
spotLocate: "spot_locate",
|
|
photoSpotSection: "photo_spot_section",
|
|
phoneSection: "phone_section",
|
|
photoList: "photo_list",
|
|
aigcComponet: "aigc_componet",
|
|
decisionSection: "decision_section",
|
|
routeWarning: "route_warning",
|
|
tourRoutes: "tour_routes",
|
|
facilitiesAlongTheWay: "facilities_along_the_way",
|
|
questionSuggest: "question_suggest",
|
|
};
|
|
|
|
for (const [keyName, keyValue] of Object.entries(expectedNewKeys)) {
|
|
assert.equal(LONG_TEXT_KEYS[keyName], keyValue, `${keyName} should be registered`);
|
|
assert.equal(
|
|
LONG_TEXT_FIELD_CONFIG.some((item) => item.key === keyValue),
|
|
true,
|
|
`${keyValue} should be in LONG_TEXT_FIELD_CONFIG`
|
|
);
|
|
}
|
|
|
|
const removedKeys = [
|
|
"content",
|
|
"guideConclusion",
|
|
"keyFacts",
|
|
"preparationSectionTitle",
|
|
"preparationSectionItems",
|
|
"sectionSuggestionTitle",
|
|
"sectionSuggestionContent",
|
|
"pitfallSectionTitle",
|
|
"pitfallSectionItems",
|
|
"viewSectionTitle",
|
|
"viewSectionItems",
|
|
"suggestionSectionTitle",
|
|
"suggestionSectionContent",
|
|
"lightReminderTitle",
|
|
"lightReminderItems",
|
|
"components",
|
|
"actionZone",
|
|
];
|
|
|
|
for (const keyName of removedKeys) {
|
|
assert.equal(
|
|
Object.prototype.hasOwnProperty.call(LONG_TEXT_KEYS, keyName),
|
|
false,
|
|
`${keyName} should be removed from LONG_TEXT_KEYS`
|
|
);
|
|
}
|
|
|
|
const oldFlatFieldValues = [
|
|
"preparation_section_title",
|
|
"preparation_section_items",
|
|
"view_section_title",
|
|
"view_section_items",
|
|
];
|
|
|
|
for (const keyValue of oldFlatFieldValues) {
|
|
assert.equal(
|
|
LONG_TEXT_FIELD_CONFIG.some((item) => item.key === keyValue),
|
|
false,
|
|
`${keyValue} should be removed from LONG_TEXT_FIELD_CONFIG`
|
|
);
|
|
}
|
|
|
|
const longTextData = createLongTextData();
|
|
appendLongTextChunk(longTextData, { contentKey: "title", contentValue: "漂流攻略" });
|
|
appendLongTextChunk(longTextData, {
|
|
contentKey: "preparation_section",
|
|
contentValue: {
|
|
preparation_section_title: "下水前",
|
|
preparation_section_items: ["带手机防水袋", "穿涉水鞋"],
|
|
},
|
|
});
|
|
appendLongTextChunk(longTextData, {
|
|
contentKey: "future_section",
|
|
contentValue: {
|
|
future_section_title: "未来新增字段",
|
|
future_section_items: ["不改 LONG_TEXT_KEYS 也展示"],
|
|
},
|
|
});
|
|
appendLongTextChunk(longTextData, {
|
|
contentKey: "content_image",
|
|
contentValue: "https://oss.nianxx.cn/XiaoQiKong/GQ00001.jpg",
|
|
});
|
|
appendLongTextChunk(longTextData, {
|
|
contentKey: "spot_locate",
|
|
contentValue: '{"spot_name":"卧龙潭","spot_longitude":"107.712345","spot_latitude":"25.251234","spot_tag":"景点"}',
|
|
});
|
|
|
|
assert.equal(getLongTextValue(longTextData, "title"), "漂流攻略");
|
|
assert.deepEqual(
|
|
getLongTextParsedValue(longTextData, "preparation_section"),
|
|
{
|
|
preparation_section_title: "下水前",
|
|
preparation_section_items: ["带手机防水袋", "穿涉水鞋"],
|
|
},
|
|
"object contentValue should be serialized and parsed"
|
|
);
|
|
assert.deepEqual(
|
|
getLongTextSections(longTextData).map((section) => section.contentKey),
|
|
["title", "preparation_section", "future_section", "content_image", "spot_locate"],
|
|
"sections should place unknown fields by receive order between configured fields"
|
|
);
|
|
assert.equal(hasLongTextExtraSections(longTextData), true);
|
|
|
|
assert.deepEqual(
|
|
getLongTextParsedValue(longTextData, "future_section"),
|
|
{
|
|
future_section_title: "未来新增字段",
|
|
future_section_items: ["不改 LONG_TEXT_KEYS 也展示"],
|
|
},
|
|
"future top-level fields should keep parsed values"
|
|
);
|
|
|
|
const mergedPayload = {
|
|
tag: "攻略",
|
|
title: "合并结构标题",
|
|
content_summary: "合并结构摘要",
|
|
preparation_section: {
|
|
preparation_section_title: "下水前",
|
|
preparation_section_items: ["带手机防水袋", "穿涉水鞋"],
|
|
},
|
|
spot_locate: {
|
|
spot_name: "卧龙潭",
|
|
spot_longitude: "107.712345",
|
|
spot_latitude: "25.251234",
|
|
spot_tag: "景点",
|
|
},
|
|
photo_list: [
|
|
{
|
|
photo_name: "桥边机位",
|
|
photo_description: "站在桥头拍",
|
|
photo_url: "https://example.com/photo.png",
|
|
},
|
|
],
|
|
photo_spot_section: "{\n\"photo_spot_section_title\":\"四个不会错的机位\",\n\"photo_spot_items\":\"- 涵碧潭半清半浊\\n- 断桥飞瀑错位玩\",\n\"best_time_suggestion\":\"下午 2 点后人少\"\n}",
|
|
phone_section: "{\n\"phone_section_title\":\"手机党看这里\",\n\"phone_section_items\":\"- 手机倒过来贴近水面\\n- 瀑布用长曝光\"\n}",
|
|
aigc_componet: {
|
|
background: "https://example.com/aigc.png",
|
|
title: "AIGC合影",
|
|
description: "生成合影",
|
|
jumpUrl: "https://example.com/aigc",
|
|
},
|
|
question_suggest: ["还要准备什么?"],
|
|
future_section: {
|
|
future_section_title: "后续新增模块",
|
|
future_section_items: ["仍然展示"],
|
|
},
|
|
};
|
|
|
|
const mergedLongTextData = createLongTextData();
|
|
appendLongTextChunk(mergedLongTextData, {
|
|
contentKey: "photo_card_payload",
|
|
contentValue: mergedPayload,
|
|
});
|
|
|
|
assert.deepEqual(
|
|
getLongTextSections(mergedLongTextData).map((section) => section.contentKey),
|
|
[
|
|
"photo_card_payload",
|
|
],
|
|
"unknown contentKey fields should be kept as a single generic section"
|
|
);
|
|
|
|
assert.deepEqual(
|
|
getLongTextParsedValue(mergedLongTextData, "photo_card_payload"),
|
|
mergedPayload,
|
|
"unknown contentKey object values should keep parsed values"
|
|
);
|
|
|
|
console.log("longTextCard display helpers passed");
|