/ src / components / NoteContent.test.tsx
NoteContent.test.tsx
  1  import { describe, it, expect } from 'vitest';
  2  import { render, screen } from '@testing-library/react';
  3  import { TestApp } from '@/test/TestApp';
  4  import { NoteContent } from './NoteContent';
  5  import type { NostrEvent } from '@nostrify/nostrify';
  6  
  7  describe('NoteContent', () => {
  8    it('linkifies URLs in kind 1 events', () => {
  9      const event: NostrEvent = {
 10        id: 'test-id',
 11        pubkey: 'test-pubkey',
 12        created_at: Math.floor(Date.now() / 1000),
 13        kind: 1,
 14        tags: [],
 15        content: 'Check out this link: https://example.com',
 16        sig: 'test-sig',
 17      };
 18  
 19      render(
 20        <TestApp>
 21          <NoteContent event={event} />
 22        </TestApp>
 23      );
 24  
 25      const link = screen.getByRole('link', { name: 'https://example.com' });
 26      expect(link).toBeInTheDocument();
 27      expect(link).toHaveAttribute('href', 'https://example.com');
 28      expect(link).toHaveAttribute('target', '_blank');
 29    });
 30  
 31    it('linkifies URLs in kind 1111 events (comments)', () => {
 32      const event: NostrEvent = {
 33        id: 'test-comment-id',
 34        pubkey: 'test-pubkey',
 35        created_at: Math.floor(Date.now() / 1000),
 36        kind: 1111,
 37        tags: [
 38          ['a', '30040:pubkey:identifier'],
 39          ['k', '30040'],
 40          ['p', 'pubkey'],
 41        ],
 42        content: 'I think the log events should be different kind numbers instead of having a `log-type` tag. That way you can use normal Nostr filters to filter the log types. Also, the `note` type should just b a kind 1111: https://nostrbook.dev/kinds/1111',
 43        sig: 'test-sig',
 44      };
 45  
 46      render(
 47        <TestApp>
 48          <NoteContent event={event} />
 49        </TestApp>
 50      );
 51  
 52      const link = screen.getByRole('link', { name: 'https://nostrbook.dev/kinds/1111' });
 53      expect(link).toBeInTheDocument();
 54      expect(link).toHaveAttribute('href', 'https://nostrbook.dev/kinds/1111');
 55      expect(link).toHaveAttribute('target', '_blank');
 56    });
 57  
 58    it('handles text without URLs correctly', () => {
 59      const event: NostrEvent = {
 60        id: 'test-id',
 61        pubkey: 'test-pubkey',
 62        created_at: Math.floor(Date.now() / 1000),
 63        kind: 1111,
 64        tags: [],
 65        content: 'This is just plain text without any links.',
 66        sig: 'test-sig',
 67      };
 68  
 69      render(
 70        <TestApp>
 71          <NoteContent event={event} />
 72        </TestApp>
 73      );
 74  
 75      expect(screen.getByText('This is just plain text without any links.')).toBeInTheDocument();
 76      expect(screen.queryByRole('link')).not.toBeInTheDocument();
 77    });
 78  
 79    it('renders hashtags as links', () => {
 80      const event: NostrEvent = {
 81        id: 'test-id',
 82        pubkey: 'test-pubkey',
 83        created_at: Math.floor(Date.now() / 1000),
 84        kind: 1,
 85        tags: [],
 86        content: 'This is a post about #nostr and #bitcoin development.',
 87        sig: 'test-sig',
 88      };
 89  
 90      render(
 91        <TestApp>
 92          <NoteContent event={event} />
 93        </TestApp>
 94      );
 95  
 96      const nostrHashtag = screen.getByRole('link', { name: '#nostr' });
 97      const bitcoinHashtag = screen.getByRole('link', { name: '#bitcoin' });
 98      
 99      expect(nostrHashtag).toBeInTheDocument();
100      expect(bitcoinHashtag).toBeInTheDocument();
101      expect(nostrHashtag).toHaveAttribute('href', '/t/nostr');
102      expect(bitcoinHashtag).toHaveAttribute('href', '/t/bitcoin');
103    });
104  
105    it('generates deterministic names for users without metadata and styles them differently', () => {
106      // Use a valid npub for testing
107      const event: NostrEvent = {
108        id: 'test-id',
109        pubkey: 'test-pubkey',
110        created_at: Math.floor(Date.now() / 1000),
111        kind: 1,
112        tags: [],
113        content: `Mentioning nostr:npub1zg69v7ys40x77y352eufp27daufrg4ncjz4ummcjx3t83y9tehhsqepuh0`,
114        sig: 'test-sig',
115      };
116  
117      render(
118        <TestApp>
119          <NoteContent event={event} />
120        </TestApp>
121      );
122  
123      // The mention should be rendered with a deterministic name
124      const mention = screen.getByRole('link');
125      expect(mention).toBeInTheDocument();
126      
127      // Should have muted styling for generated names (gray instead of blue)
128      expect(mention).toHaveClass('text-gray-500');
129      expect(mention).not.toHaveClass('text-blue-500');
130      
131      // The text should start with @ and contain a generated name (not a truncated npub)
132      const linkText = mention.textContent;
133      expect(linkText).not.toMatch(/^@npub1/); // Should not be a truncated npub
134      expect(linkText).toEqual("@Swift Falcon");
135    });
136  });