|
4 | 4 | */ |
5 | 5 |
|
6 | 6 | import { describe, it, expect, afterEach, vi } from 'vitest'; |
7 | | -import { generateArticleHTML, generateArticleLanguageSwitcher, generateSiteFooter } from '../scripts/article-template.js'; |
| 7 | +import { generateArticleHTML, generateArticleLanguageSwitcher, generateSiteFooter, fixHtmlNesting } from '../scripts/article-template.js'; |
8 | 8 | import articleTemplateDefault from '../scripts/article-template.js'; |
9 | 9 | import type { Language } from '../scripts/types/language.js'; |
10 | 10 | import type { ArticleData, ArticleCategory, EventGridItem, WatchPoint } from '../scripts/types/article.js'; |
@@ -890,4 +890,48 @@ describe('Article Template', () => { |
890 | 890 | expect(typeof articleTemplateDefault.generateSiteFooter).toBe('function'); |
891 | 891 | }); |
892 | 892 | }); |
| 893 | + |
| 894 | + describe('fixHtmlNesting', () => { |
| 895 | + it('should remove orphaned </p> after </ul>', () => { |
| 896 | + const input = '<p>intro</p><ul><li>item</li></ul></p>'; |
| 897 | + expect(fixHtmlNesting(input)).toBe('<p>intro</p><ul><li>item</li></ul>'); |
| 898 | + }); |
| 899 | + |
| 900 | + it('should remove orphaned </p> after </ol>', () => { |
| 901 | + const input = '<p>intro</p><ol><li>step</li></ol></p>'; |
| 902 | + expect(fixHtmlNesting(input)).toBe('<p>intro</p><ol><li>step</li></ol>'); |
| 903 | + }); |
| 904 | + |
| 905 | + it('should handle whitespace between </ul> and </p>', () => { |
| 906 | + const input = '<ul><li>x</li></ul> </p>'; |
| 907 | + expect(fixHtmlNesting(input)).toBe('<ul><li>x</li></ul>'); |
| 908 | + }); |
| 909 | + |
| 910 | + it('should leave valid </p> tags unchanged', () => { |
| 911 | + const input = '<p>valid paragraph</p><p>another</p>'; |
| 912 | + expect(fixHtmlNesting(input)).toBe('<p>valid paragraph</p><p>another</p>'); |
| 913 | + }); |
| 914 | + |
| 915 | + it('should fix the pattern in rendered article HTML body', () => { |
| 916 | + const data: MockArticleData = { |
| 917 | + ...mockArticleData, |
| 918 | + content: '<p>Key proposals include:</p><ul><li><strong>Item A</strong></li></ul></p>' |
| 919 | + }; |
| 920 | + const html = generateArticleHTML(data as unknown as ArticleData) as string; |
| 921 | + expect(html).not.toContain('</ul></p>'); |
| 922 | + expect(html).not.toContain('</ol></p>'); |
| 923 | + }); |
| 924 | + |
| 925 | + it('should fix the pattern in JSON-LD articleBody', () => { |
| 926 | + const data: MockArticleData = { |
| 927 | + ...mockArticleData, |
| 928 | + content: '<p>Key proposals include:</p><ul><li><strong>Item A</strong></li></ul></p>' |
| 929 | + }; |
| 930 | + const html = generateArticleHTML(data as unknown as ArticleData) as string; |
| 931 | + const jsonLdMatch = html.match(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/); |
| 932 | + expect(jsonLdMatch).not.toBeNull(); |
| 933 | + // The escaped form of </ul></p> should not appear in JSON-LD articleBody |
| 934 | + expect(jsonLdMatch![1]).not.toContain('</ul></p>'); |
| 935 | + }); |
| 936 | + }); |
893 | 937 | }); |
0 commit comments