A calm place to write long-form, and publish it to the open social web.
skypress.blog/
1import { describe, expect, it } from 'vitest';
2import { detectBioSegments, safeHttpHref } from './rich-text';
3
4describe( 'detectBioSegments', () => {
5 it( 'returns a single text segment for plain prose', () => {
6 expect( detectBioSegments( 'Just a writer.' ) ).toEqual( [
7 { type: 'text', text: 'Just a writer.' },
8 ] );
9 } );
10
11 it( 'returns an empty array for blank input', () => {
12 expect( detectBioSegments( ' ' ) ).toEqual( [] );
13 } );
14
15 it( 'linkifies a full URL and keeps trailing punctuation out of the link', () => {
16 expect( detectBioSegments( 'Visit https://example.com.' ) ).toEqual( [
17 { type: 'text', text: 'Visit ' },
18 { type: 'link', text: 'https://example.com', href: 'https://example.com' },
19 { type: 'text', text: '.' },
20 ] );
21 } );
22
23 it( 'linkifies a bare domain with an https href and bare display text', () => {
24 expect( detectBioSegments( 'example.com' ) ).toEqual( [
25 { type: 'link', text: 'example.com', href: 'https://example.com' },
26 ] );
27 } );
28
29 it( 'links a mention to its Bluesky profile by handle', () => {
30 expect( detectBioSegments( 'hi @alice.bsky.social' ) ).toEqual( [
31 { type: 'text', text: 'hi ' },
32 {
33 type: 'link',
34 text: '@alice.bsky.social',
35 href: 'https://mu.social/profile/alice.bsky.social',
36 },
37 ] );
38 } );
39
40 it( 'links a hashtag to its Bluesky hashtag page', () => {
41 expect( detectBioSegments( 'love #design' ) ).toEqual( [
42 { type: 'text', text: 'love ' },
43 { type: 'link', text: '#design', href: 'https://mu.social/hashtag/design' },
44 ] );
45 } );
46
47 it( 'orders mixed text, url, mention and tag segments correctly', () => {
48 expect(
49 detectBioSegments( 'me @alice.bsky.social #design example.com' )
50 ).toEqual( [
51 { type: 'text', text: 'me ' },
52 {
53 type: 'link',
54 text: '@alice.bsky.social',
55 href: 'https://mu.social/profile/alice.bsky.social',
56 },
57 { type: 'text', text: ' ' },
58 { type: 'link', text: '#design', href: 'https://mu.social/hashtag/design' },
59 { type: 'text', text: ' ' },
60 { type: 'link', text: 'example.com', href: 'https://example.com' },
61 ] );
62 } );
63} );
64
65describe( 'safeHttpHref', () => {
66 it( 'passes http and https through unchanged', () => {
67 expect( safeHttpHref( 'https://example.com' ) ).toBe( 'https://example.com' );
68 expect( safeHttpHref( 'http://example.com/x' ) ).toBe( 'http://example.com/x' );
69 } );
70
71 it( 'rejects non-http(s) schemes and garbage', () => {
72 expect( safeHttpHref( 'javascript:alert(1)' ) ).toBeNull();
73 expect( safeHttpHref( 'ftp://example.com' ) ).toBeNull();
74 expect( safeHttpHref( 'not a url' ) ).toBeNull();
75 } );
76} );