import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { pathToFileURL } from "node:url"; import { fileURLToPath } from "node:url"; const scriptDir = dirname(fileURLToPath(import.meta.url)); const componentPath = resolve( scriptDir, "../src/pages/ChatMain/ChatLongAnswer/ParsedValueView.vue" ); const detailPagePath = resolve( scriptDir, "../src/pages/ChatMain/ChatLongAnswer/index.vue" ); const longTextCardPath = resolve(scriptDir, "../src/utils/longTextCard.js"); const componentSource = readFileSync(componentPath, "utf8"); const detailPageSource = readFileSync(detailPagePath, "utf8"); const longTextCardSource = readFileSync(longTextCardPath, "utf8"); const { getLongTextSections } = await import(pathToFileURL(longTextCardPath)); assert.match( longTextCardSource, /export\s+const\s+normalizeLongTextSpotLocate\s*=/, "longTextCard should export normalizeLongTextSpotLocate for malformed spot_locate keys" ); assert.match( longTextCardSource, /export\s+const\s+normalizeLongTextQuestionSuggest\s*=/, "longTextCard should export normalizeLongTextQuestionSuggest for JSON-string question_suggest values" ); assert.match( longTextCardSource, /export\s+const\s+normalizeLongTextContentImage\s*=/, "longTextCard should export normalizeLongTextContentImage for string/object content_image values" ); assert.match( componentSource, /entry\.type\s*===\s*["']content-image["']/, "ParsedValueView should render content_image with the dedicated image style" ); assert.match( componentSource, /entry\.type\s*===\s*["']spot-locate["']/, "ParsedValueView should render spot_locate with the dedicated POI action card" ); assert.match( componentSource, /entry\.type\s*===\s*["']question-suggest["']/, "ParsedValueView should render question_suggest with dedicated FAQ chips" ); assert.match( componentSource, /sendReply\(question\)/, "question_suggest chips should send the selected follow-up question" ); assert.match( componentSource, /openMap\(entry\.value\)/, "spot_locate action card should open the normalized map location" ); const hiddenDetailKeysMatch = detailPageSource.match( /const\s+HIDDEN_DETAIL_SECTION_KEYS\s*=\s*\[([\s\S]*?)\];/ ); assert.ok( hiddenDetailKeysMatch, "long answer detail page should define HIDDEN_DETAIL_SECTION_KEYS" ); assert.doesNotMatch( hiddenDetailKeysMatch[1], /LONG_TEXT_KEYS\.contentSummary/, "long answer detail page should not hide content_summary" ); const ignoredFieldKeysMatch = componentSource.match( /const\s+IGNORED_FIELD_KEYS\s*=\s*\[([\s\S]*?)\];/ ); assert.ok( ignoredFieldKeysMatch, "ParsedValueView should define IGNORED_FIELD_KEYS" ); assert.doesNotMatch( ignoredFieldKeysMatch[1], /["']content_summary["']/, "ParsedValueView should not ignore content_summary" ); const receivedKeys = [ "tag", "title", "content_summary", "content_image", "view_section_title", "view_section_items", "suggestion_section_title", "suggestion_section_content", "light_reminder_title", "light_reminder_items", "spot_locate", "question_suggest", ]; const longTextData = { values: {}, parsedValues: {}, }; receivedKeys.forEach((key) => { longTextData.values[key] = key; }); assert.deepEqual( getLongTextSections(longTextData).map((section) => section.contentKey), receivedKeys, "long text detail sections should preserve server receive order, including configured fields after extra fields" );