app/document_test.go
122 lines · 5992 bytes
1package app
2
3import (
4 "strings"
5 "testing"
6
7 "github.com/krazywarez/devianter"
8)
9
10// docText wraps a document body the way DeviantArt stores it.
11func docText(body string) devianter.Text {
12 var t devianter.Text
13 t.Html.Markup = `{"version":1,"document":{"type":"doc","content":[` + body + `]},"features":[]}`
14 return t
15}
16
17func withDocConfig(t *testing.T) {
18 t.Helper()
19 proxy, uri, nsfw := CFG.Proxy, CFG.URI, CFG.Nsfw
20 CFG.Proxy, CFG.URI, CFG.Nsfw = true, "/", true
21 t.Cleanup(func() { CFG.Proxy, CFG.URI, CFG.Nsfw = proxy, uri, nsfw })
22}
23
24// TestDocumentParagraphsMarksAndBreaks uses the shape seen on live
25// descriptions: paragraphs of text with link, underline and italic marks.
26func TestDocumentParagraphsMarksAndBreaks(t *testing.T) {
27 withDocConfig(t)
28 out := ParseDescription("http://localhost", docText(`
29 {"type":"paragraph","attrs":{"textAlign":"center"},"content":[
30 {"type":"text","text":"| "},
31 {"type":"text","marks":[{"type":"link","attrs":{"href":"https://www.deviantart.com/users/outgoing?https://www.patreon.com/x","target":"_blank"}},{"type":"underline"}],"text":"PATREON"},
32 {"type":"hardBreak"},
33 {"type":"text","marks":[{"type":"italic"}],"text":"Finished <YCH> for "},
34 {"type":"text","marks":[{"type":"textStyle"}],"text":"plain"}
35 ]}`))
36 for _, want := range []string{
37 `<p>| <a target="_blank" href="https://www.patreon.com/x"><u>PATREON</u></a><br><i>Finished <YCH> for </i>plain</p>`,
38 } {
39 if !strings.Contains(out, want) {
40 t.Errorf("output lacks %q:\n%s", want, out)
41 }
42 }
43}
44
45func TestDocumentBlocksAndLists(t *testing.T) {
46 withDocConfig(t)
47 out := ParseDescription("http://localhost", docText(`
48 {"type":"heading","attrs":{"level":1},"content":[{"type":"text","text":"Title"}]},
49 {"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"one"}]}]}]},
50 {"type":"orderedList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"two"}]}]}]},
51 {"type":"blockquote","content":[{"type":"paragraph","content":[{"type":"text","text":"quoted"}]}]},
52 {"type":"codeBlock","content":[{"type":"text","text":"x < y"}]},
53 {"type":"horizontalRule"},
54 {"type":"mystery","content":[{"type":"text","text":"still shown"}]},
55 {"type":"mysteryLeaf","attrs":{"x":1}}`))
56 for _, want := range []string{"<h2>Title</h2>", "<ul><li><p><b>one</b></p></li></ul>", "<ol><li><p>two</p></li></ol>", "<blockquote><p>quoted</p></blockquote>", "<pre>x < y</pre>", "<hr>", "still shown"} {
57 if !strings.Contains(out, want) {
58 t.Errorf("output lacks %q:\n%s", want, out)
59 }
60 }
61}
62
63// TestDocumentEmotes is the new-format half of #6: an official emote with a
64// source image maps to the emote route by file name, one without a source
65// falls back to its code.
66func TestDocumentEmotes(t *testing.T) {
67 withDocConfig(t)
68 out := ParseDescription("http://localhost", docText(`
69 {"type":"paragraph","content":[
70 {"type":"da-emote","attrs":{"data-emote":":star:","data-type":"official","src":"https://e.deviantart.net/emoticons/s/star_full.gif","width":17,"height":16,"url":null,"title":null}},
71 {"type":"da-emote","attrs":{"data-emote":":love:","data-type":"official","src":null,"width":null,"height":null,"url":null,"title":null}},
72 {"type":"da-emote","attrs":{"data-emote":"","data-type":"custom","src":null}}
73 ]}`))
74 for _, want := range []string{`src="http://localhost/media/emojitar/star_full?type=e" alt=":star:"`, `src="http://localhost/media/emojitar/love?type=e" alt=":love:"`} {
75 if !strings.Contains(out, want) {
76 t.Errorf("output lacks %q:\n%s", want, out)
77 }
78 }
79 if strings.Count(out, "<img") != 2 {
80 t.Errorf("want 2 images (the nameless emote renders nothing):\n%s", out)
81 }
82}
83
84func TestDocumentEmbeddedDeviationAndGif(t *testing.T) {
85 withDocConfig(t)
86 out := ParseDescription("http://localhost", docText(`
87 {"type":"paragraph","content":[
88 {"type":"da-deviation-thumb","attrs":{"cropping":"fill","deviation":{"deviationId":1276762071,"url":"https://www.deviantart.com/ashiori-chan/art/CLOSED-YCH-Portrait-auction-1276762071","title":"[CLOSED] YCH","author":{"username":"AShiori-chan"},"media":{"baseUri":"https://images-wixmp-abc.wixmp.com/f/u/x.png","prettyName":"x_by_y","token":["tok.en.sig"],"types":[{"t":"fullview","h":1920,"w":1280}]}}}},
89 {"type":"da-gif","attrs":{"url":"https://media4.giphy.com/media/x/giphy.mp4","width":480,"height":362}}
90 ]}`))
91 for _, want := range []string{`<a href="http://localhost/post/ashiori-chan/CLOSED-YCH-Portrait-auction-1276762071">`, `src="http://localhost/media/file/abc/`, `alt="AShiori-chan - [CLOSED] YCH"`, `<a target="_blank" href="https://media4.giphy.com/media/x/giphy.mp4">[GIF]</a>`} {
92 if !strings.Contains(out, want) {
93 t.Errorf("output lacks %q:\n%s", want, out)
94 }
95 }
96}
97
98func TestDocumentHidesEmbeddedNSFWWhenDisabled(t *testing.T) {
99 withDocConfig(t)
100 CFG.Nsfw = false
101 out := ParseDescription("http://localhost", docText(`
102 {"type":"paragraph","content":[{"type":"da-deviation","attrs":{"deviation":{"deviationId":1,"isMature":true,"url":"https://www.deviantart.com/a/art/b-1","title":"secret","author":{"username":"a"}}}}]}`))
103 if strings.Contains(out, "secret") {
104 t.Errorf("mature embed shown with nsfw off:\n%s", out)
105 }
106}
107
108// TestDraftJSAndHTMLStillDispatch pins that the two older formats still reach
109// their own parsers.
110func TestDraftJSAndHTMLStillDispatch(t *testing.T) {
111 withDocConfig(t)
112 var draft devianter.Text
113 draft.Html.Markup = `{"blocks":[{"text":"draft text","type":"unstyled","inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}`
114 if out := ParseDescription("http://localhost", draft); !strings.Contains(out, "draft text") {
115 t.Errorf("Draft.js description not rendered:\n%s", out)
116 }
117 var legacy devianter.Text
118 legacy.Html.Markup = `plain <b>html</b>`
119 if out := ParseDescription("http://localhost", legacy); !strings.Contains(out, "<b>html</b>") {
120 t.Errorf("HTML description not rendered:\n%s", out)
121 }
122}