A calm place to write long-form, and publish it to the open social web.
skypress.blog/
1import { describe, expect, it } from 'vitest';
2import { sanitizeArticleHtml } from './sanitize';
3
4describe( 'sanitizeArticleHtml', () => {
5 it( 'strips <script> and inline event handlers (untrusted PDS content)', () => {
6 const dirty = '<p>Hi</p><script>alert(1)</script><img src="x" onerror="alert(2)">';
7 const clean = sanitizeArticleHtml( dirty );
8 expect( clean ).toContain( '<p>Hi</p>' );
9 expect( clean ).not.toContain( '<script' );
10 expect( clean ).not.toContain( 'onerror' );
11 expect( clean ).not.toContain( 'alert(2)' );
12 } );
13
14 it( 'drops javascript: URLs but keeps safe links + images', () => {
15 const dirty =
16 '<a href="javascript:alert(1)">x</a><a href="https://ok.example">ok</a><img src="https://cdn.example/a.png" alt="a">';
17 const clean = sanitizeArticleHtml( dirty );
18 expect( clean ).not.toContain( 'javascript:' );
19 expect( clean ).toContain( 'href="https://ok.example"' );
20 expect( clean ).toContain( '<img' );
21 expect( clean ).toContain( 'src="https://cdn.example/a.png"' );
22 } );
23
24 it( 'preserves the curated blocks’ tags + classes', () => {
25 const html =
26 '<h2 class="wp-block-heading">T</h2><pre class="wp-block-code"><code>x</code></pre><blockquote class="wp-block-quote"><p>q</p></blockquote>';
27 const clean = sanitizeArticleHtml( html );
28 expect( clean ).toContain( '<h2 class="wp-block-heading">' );
29 expect( clean ).toContain( '<pre class="wp-block-code">' );
30 expect( clean ).toContain( '<blockquote class="wp-block-quote">' );
31 } );
32
33 it( 'hardens external links with rel + target', () => {
34 const clean = sanitizeArticleHtml( '<a href="https://x.example">x</a>' );
35 expect( clean ).toContain( 'rel="noopener noreferrer nofollow ugc"' );
36 expect( clean ).toContain( 'target="_blank"' );
37 } );
38
39 it( 'keeps a mention link (class + href) but strips its data-did', () => {
40 const dirty =
41 '<p>Hi <a class="skypress-mention" href="https://bsky.app/profile/alice.bsky.social" data-did="did:plc:alice">@alice.bsky.social</a></p>';
42 const clean = sanitizeArticleHtml( dirty );
43 expect( clean ).toContain( 'class="skypress-mention"' );
44 expect( clean ).toContain( 'href="https://bsky.app/profile/alice.bsky.social"' );
45 expect( clean ).not.toContain( 'data-did' );
46 expect( clean ).toContain( '@alice.bsky.social' );
47 } );
48} );