18 changed files with 432 additions and 127 deletions
@ -0,0 +1,77 @@ |
|||||||
|
import { describe, expect, it } from 'vitest' |
||||||
|
import { kinds } from 'nostr-tools' |
||||||
|
import { eventMatchesTopicOrContentHashtag, formatTopicMapBubbleLabel, isValidNormalizedTopicKey, normalizedKeyMatchesHashtagPattern, normalizeTopic, relayTopicTagFilterValues } from '@/lib/discussion-topics' |
||||||
|
|
||||||
|
describe('eventMatchesTopicOrContentHashtag', () => { |
||||||
|
it('matches normalized t tags', () => { |
||||||
|
const ev = { |
||||||
|
kind: kinds.ShortTextNote, |
||||||
|
tags: [['t', 'catholic']], |
||||||
|
content: 'hello', |
||||||
|
id: 'a'.repeat(64), |
||||||
|
pubkey: 'b'.repeat(64), |
||||||
|
sig: 'c'.repeat(128), |
||||||
|
created_at: 1 |
||||||
|
} |
||||||
|
expect(eventMatchesTopicOrContentHashtag(ev, 'catholic')).toBe(true) |
||||||
|
}) |
||||||
|
|
||||||
|
it('matches #hashtag in content', () => { |
||||||
|
const ev = { |
||||||
|
kind: kinds.ShortTextNote, |
||||||
|
tags: [], |
||||||
|
content: 'Prayers for the #catholic church today', |
||||||
|
id: 'a'.repeat(64), |
||||||
|
pubkey: 'b'.repeat(64), |
||||||
|
sig: 'c'.repeat(128), |
||||||
|
created_at: 1 |
||||||
|
} |
||||||
|
expect(eventMatchesTopicOrContentHashtag(ev, 'catholic')).toBe(true) |
||||||
|
}) |
||||||
|
|
||||||
|
it('rejects plain text without t tag or #hashtag', () => { |
||||||
|
const ev = { |
||||||
|
kind: kinds.ShortTextNote, |
||||||
|
tags: [], |
||||||
|
content: 'That catholic school is weird', |
||||||
|
id: 'a'.repeat(64), |
||||||
|
pubkey: 'b'.repeat(64), |
||||||
|
sig: 'c'.repeat(128), |
||||||
|
created_at: 1 |
||||||
|
} |
||||||
|
expect(eventMatchesTopicOrContentHashtag(ev, 'catholic')).toBe(false) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('isValidNormalizedTopicKey', () => { |
||||||
|
it('accepts normalized topic keys', () => { |
||||||
|
expect(isValidNormalizedTopicKey('nostr')).toBe(true) |
||||||
|
expect(isValidNormalizedTopicKey('grownostr')).toBe(true) |
||||||
|
}) |
||||||
|
|
||||||
|
it('rejects empty, numeric-only, and invalid characters', () => { |
||||||
|
expect(isValidNormalizedTopicKey('')).toBe(false) |
||||||
|
expect(isValidNormalizedTopicKey('123')).toBe(false) |
||||||
|
expect(isValidNormalizedTopicKey('-bad')).toBe(false) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('formatTopicMapBubbleLabel', () => { |
||||||
|
it('shows readable text without a hash prefix', () => { |
||||||
|
expect(formatTopicMapBubbleLabel('decent-newsroom')).toBe('decent newsroom') |
||||||
|
expect(formatTopicMapBubbleLabel('nostr')).toBe('nostr') |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('relayTopicTagFilterValues', () => { |
||||||
|
it('includes plural t-tag variants for singularized map keys', () => { |
||||||
|
expect(relayTopicTagFilterValues('jesu')).toEqual(expect.arrayContaining(['jesu', 'jesus'])) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('normalizedKeyMatchesHashtagPattern', () => { |
||||||
|
it('matches valid ascii hashtag bodies', () => { |
||||||
|
expect(normalizedKeyMatchesHashtagPattern('imwald')).toBe(true) |
||||||
|
expect(normalizedKeyMatchesHashtagPattern('')).toBe(false) |
||||||
|
}) |
||||||
|
}) |
||||||
@ -0,0 +1,41 @@ |
|||||||
|
import { describe, expect, it } from 'vitest' |
||||||
|
import { kinds } from 'nostr-tools' |
||||||
|
import { DEFAULT_FEED_SHOW_KINDS } from '@/constants' |
||||||
|
import { buildTopicKeywordBubbles } from './TopicKeywordHeatMap' |
||||||
|
|
||||||
|
function note(pubkey: string, tags: string[][], content = '') { |
||||||
|
return { |
||||||
|
kind: kinds.ShortTextNote, |
||||||
|
pubkey, |
||||||
|
content, |
||||||
|
tags, |
||||||
|
id: `${pubkey.slice(0, 8)}${'a'.repeat(56)}`, |
||||||
|
sig: 'b'.repeat(128), |
||||||
|
created_at: 1_700_000_000 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
describe('buildTopicKeywordBubbles', () => { |
||||||
|
it('ranks pubkeys by how often they used the topic', () => { |
||||||
|
const pkA = 'a'.repeat(64) |
||||||
|
const pkB = 'b'.repeat(64) |
||||||
|
const pkC = 'c'.repeat(64) |
||||||
|
const bubbles = buildTopicKeywordBubbles( |
||||||
|
[ |
||||||
|
note(pkA, [['t', 'nostr']]), |
||||||
|
note(pkA, [['t', 'nostr']]), |
||||||
|
note(pkB, [['t', 'nostr']]), |
||||||
|
note(pkC, [], 'hello #nostr'), |
||||||
|
note(pkC, [], 'again #nostr') |
||||||
|
], |
||||||
|
DEFAULT_FEED_SHOW_KINDS, |
||||||
|
true, |
||||||
|
true, |
||||||
|
true |
||||||
|
) |
||||||
|
const nostr = bubbles.find((b) => b.key === 'nostr') |
||||||
|
expect(nostr?.pubkeys[0]).toBe(pkA) |
||||||
|
expect(nostr?.pubkeys).toContain(pkC) |
||||||
|
expect(nostr?.pubkeys).toContain(pkB) |
||||||
|
}) |
||||||
|
}) |
||||||
Loading…
Reference in new issue