Daily Bluesky bot for AT Mot. Invites players and congratulates yesterday's solvers.
1import { describe, it, expect } from 'vitest';
2import { linkFacet, tagFacets } from '../src/facets.js';
3
4const URL = 'https://atmot.herve.bzh'; // 23 bytes (ASCII)
5
6describe('linkFacet', () => {
7 it('computes ASCII byte offsets', () => {
8 const text = `Play: ${URL}`;
9 expect(linkFacet(text, URL)).toEqual([
10 {
11 index: { byteStart: 6, byteEnd: 29 },
12 features: [{ $type: 'app.bsky.richtext.facet#link', uri: URL }],
13 },
14 ]);
15 });
16
17 it('counts multi-byte characters before the url (🟩 is 4 bytes)', () => {
18 const text = `🟩 ${URL}`;
19 expect(linkFacet(text, URL)).toEqual([
20 {
21 index: { byteStart: 5, byteEnd: 28 },
22 features: [{ $type: 'app.bsky.richtext.facet#link', uri: URL }],
23 },
24 ]);
25 });
26
27 it('returns [] when the url is not present', () => {
28 expect(linkFacet('no link here', URL)).toEqual([]);
29 });
30});
31
32describe('tagFacets', () => {
33 it('emits a #tag facet per hashtag (range covers the #, tag has no #)', () => {
34 expect(tagFacets('#WordGame #atproto')).toEqual([
35 {
36 index: { byteStart: 0, byteEnd: 9 },
37 features: [{ $type: 'app.bsky.richtext.facet#tag', tag: 'WordGame' }],
38 },
39 {
40 index: { byteStart: 10, byteEnd: 18 },
41 features: [{ $type: 'app.bsky.richtext.facet#tag', tag: 'atproto' }],
42 },
43 ]);
44 });
45
46 it('counts multi-byte characters before a hashtag', () => {
47 // "🟩 " is 5 bytes, so "#atproto" starts at byte 5.
48 expect(tagFacets('🟩 #atproto')).toEqual([
49 {
50 index: { byteStart: 5, byteEnd: 13 },
51 features: [{ $type: 'app.bsky.richtext.facet#tag', tag: 'atproto' }],
52 },
53 ]);
54 });
55
56 it('does NOT treat an all-digit token like a puzzle number as a tag', () => {
57 expect(tagFacets('AT Mot #3 is live')).toEqual([]);
58 });
59
60 it('only matches a hashtag at a word boundary, not mid-word', () => {
61 expect(tagFacets('foo#bar')).toEqual([]);
62 });
63
64 it('returns [] when there are no hashtags', () => {
65 expect(tagFacets('no tags here')).toEqual([]);
66 });
67});