121 lines
3.7 KiB
Go
121 lines
3.7 KiB
Go
package browse
|
|
|
|
// Internal test: it pins the unexported converter's exact output so
|
|
// formatting drift is caught by the package itself.
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestHTMLToMarkdown(t *testing.T) {
|
|
t.Parallel()
|
|
cases := []struct {
|
|
name string
|
|
html string
|
|
want string
|
|
}{
|
|
{
|
|
name: "headings and paragraphs",
|
|
html: `<html><body><h1>Title</h1><p>First.</p><p>Second <strong>bold</strong> and <em>italic</em>.</p></body></html>`,
|
|
want: "# Title\n\nFirst.\n\nSecond **bold** and *italic*.",
|
|
},
|
|
{
|
|
name: "relative links resolve against the page",
|
|
html: `<body><p><a href="/docs/guide">Guide</a> and <a href="https://abs.test/x">abs</a></p></body>`,
|
|
want: "[Guide](https://page.test/docs/guide) and [abs](https://abs.test/x)",
|
|
},
|
|
{
|
|
name: "dead links keep their text only",
|
|
html: `<body><p><a href="#">top</a> <a href="javascript:go()">go</a></p></body>`,
|
|
want: "top go",
|
|
},
|
|
{
|
|
name: "lists nest and order",
|
|
html: `<body><ul><li>one</li><li>two<ol start="3"><li>deep</li></ol></li></ul></body>`,
|
|
want: "- one\n- two\n 3. deep",
|
|
},
|
|
{
|
|
name: "blockquote prefixes every line",
|
|
html: `<body><blockquote><p>line one</p><p>line two</p></blockquote></body>`,
|
|
want: "> line one\n>\n> line two",
|
|
},
|
|
{
|
|
name: "pre renders as a fenced block",
|
|
html: `<body><pre>keep
|
|
spacing</pre></body>`,
|
|
want: "```\nkeep\n spacing\n```",
|
|
},
|
|
{
|
|
name: "tables render GFM",
|
|
html: `<body><table><thead><tr><th>Name</th><th>Size</th></tr></thead>` +
|
|
`<tbody><tr><td>a|b</td><td>1</td></tr></tbody></table></body>`,
|
|
want: "| Name | Size |\n| --- | --- |\n| a\\|b | 1 |",
|
|
},
|
|
{
|
|
name: "script, style and hidden content vanish",
|
|
html: `<body><style>p{}</style><script>var x=1;</script>` +
|
|
`<p hidden>nope</p><p aria-hidden="true">nor this</p><p>visible</p></body>`,
|
|
want: "visible",
|
|
},
|
|
{
|
|
name: "images keep alt text",
|
|
html: `<body><p><img src="/img/logo.png" alt="Logo"> and <img src="/img/x.png"></p></body>`,
|
|
want: " and ",
|
|
},
|
|
{
|
|
name: "consecutive blocks collapse to one blank line",
|
|
html: `<body><div><p>a</p></div><div><p>b</p></div></body>`,
|
|
want: "a\n\nb",
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
got, _, err := htmlToMarkdown([]byte(tc.html), "https://page.test/")
|
|
if err != nil {
|
|
t.Fatalf("htmlToMarkdown: %v", err)
|
|
}
|
|
if got != tc.want {
|
|
t.Errorf("markdown =\n%q\nwant\n%q", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestHTMLToMarkdownMetadata(t *testing.T) {
|
|
t.Parallel()
|
|
html := `<!doctype html><html lang="sv"><head>
|
|
<title>Meta sidan</title>
|
|
<meta name="description" content="Beskrivning.">
|
|
<meta name="robots" content="noai">
|
|
<link rel="canonical" href="https://page.test/canon">
|
|
</head><body>
|
|
<h1>Rubrik</h1>
|
|
<p>lite text att räkna</p>
|
|
<script src="/x.js"></script><img src="/y.png" alt="y">
|
|
</body></html>`
|
|
|
|
_, meta, err := htmlToMarkdown([]byte(html), "https://page.test/")
|
|
if err != nil {
|
|
t.Fatalf("htmlToMarkdown: %v", err)
|
|
}
|
|
if meta.Title != "Meta sidan" || meta.Description != "Beskrivning." {
|
|
t.Errorf("head metadata wrong: %+v", meta)
|
|
}
|
|
if meta.Lang != "sv" || meta.Canonical != "https://page.test/canon" {
|
|
t.Errorf("lang/canonical wrong: %+v", meta)
|
|
}
|
|
if meta.H1 != "Rubrik" {
|
|
t.Errorf("h1 = %q", meta.H1)
|
|
}
|
|
if meta.WordCount != 5 || meta.TextLength == 0 {
|
|
t.Errorf("text stats wrong: words=%d chars=%d", meta.WordCount, meta.TextLength)
|
|
}
|
|
if meta.ScriptCount != 1 || meta.ImageCount != 1 {
|
|
t.Errorf("element counts wrong: %+v", meta)
|
|
}
|
|
if !strings.Contains(strings.ToLower(meta.Robots), "noai") {
|
|
t.Errorf("robots = %q", meta.Robots)
|
|
}
|
|
}
|