mirror of
https://github.com/pionxzh/chatgpt-exporter.git
synced 2026-10-02 02:47:35 -05:00
A conversation title such as `Fix <Draft>` was inserted as markup into the page title, the header and the metadata section, which hid the text or broke the page. Escape the title and every metadata name and value.
36 lines
1.6 KiB
TypeScript
36 lines
1.6 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { fillTemplate, metaDetailsHtml } from '../src/exporter/htmlTemplate'
|
|
|
|
describe('fillTemplate', () => {
|
|
it('inserts values verbatim', () => {
|
|
expect(fillTemplate('<p>{{content}}</p>', { content: 'E = $$mc^2$$, sed "s/x/$&/", echo $$' }))
|
|
.toBe('<p>E = $$mc^2$$, sed "s/x/$&/", echo $$</p>')
|
|
})
|
|
|
|
it('does not fill placeholders that come from a value', () => {
|
|
expect(fillTemplate('{{title}}: {{content}}', { title: 'T', content: 'Handlebars uses {{title}}' }))
|
|
.toBe('T: Handlebars uses {{title}}')
|
|
})
|
|
|
|
it('fills every placeholder in the HTML template', () => {
|
|
const template = readFileSync(new URL('../src/template.html', import.meta.url), 'utf8')
|
|
const names = ['title', 'date', 'time', 'source', 'lang', 'theme', 'avatar', 'details', 'content']
|
|
const html = fillTemplate(template, Object.fromEntries(names.map(name => [name, `<${name}>`])))
|
|
expect(html).not.toMatch(/\{\{\w+\}\}/)
|
|
})
|
|
})
|
|
|
|
describe('metaDetailsHtml', () => {
|
|
it('escapes names and values', () => {
|
|
const html = metaDetailsHtml([['<b>title</b>', 'Fix <Draft> & "notes"'], ['source', 'https://chatgpt.com/c/1?a=1&b=2']])
|
|
expect(html).toContain('<div><b>title</b></div><div>Fix <Draft> & "notes"</div>')
|
|
expect(html).toContain('<div>https://chatgpt.com/c/1?a=1&b=2</div>')
|
|
expect(html).not.toContain('<Draft>')
|
|
})
|
|
|
|
it('renders nothing without metadata', () => {
|
|
expect(metaDetailsHtml([])).toBe('')
|
|
})
|
|
})
|