A simple Ruby server using Sinatra that serves Bluesky custom feeds
at master 183 lines 6.1 kB view raw
1require 'spec_helper' 2 3describe BlueFactory::OutputGenerator do 4 subject { BlueFactory::OutputGenerator.new } 5 6 let(:post_uri) { 'at://did:plc:abc123/app.bsky.feed.post/def456' } 7 let(:second_post_uri) { 'at://did:plc:abc123/app.bsky.feed.post/ghi789' } 8 9 it 'should generate feed output from received get_posts response' do 10 response = { 11 posts: [ 12 { 13 :post => "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.post/3lwtzoigbp22x", 14 :reason => { :pin => true } 15 }, 16 "at://did:plc:rnpkyqnmsw4ipey6eotbdnnf/app.bsky.feed.post/3md4khzlybs2f", 17 "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.post/3md5h3jg6as2r", 18 { 19 :post => "at://did:plc:4adlzwqtkv4dirxjwq4c3tlm/app.bsky.feed.post/3mcvrvtlk2j2t", 20 :reason => { :repost => "at://did:plc:vmt7o7y6titkqzzxav247zrn/app.bsky.feed.repost/3md54l2q7zc2w" }, 21 :context => "17480484288:28" 22 }, 23 "at://did:plc:hpv2yni36g2b4ymwsdg2uwre/app.bsky.feed.post/3md4xjrcmj22h", 24 { 25 :post => "at://did:plc:2zziubqb5v7bdw2ahteej7wr/app.bsky.feed.post/3md4wfrap6t2c" 26 } 27 ], 28 cursor: "2026-01-24T00:32:27.137Z", 29 req_id: "17480484288" 30 } 31 32 output = subject.generate(response) 33 34 output.should == { 35 feed: [ 36 { 37 :post => "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.post/3lwtzoigbp22x", 38 :reason => { "$type" => "app.bsky.feed.defs#skeletonReasonPin" } 39 }, 40 { :post => "at://did:plc:rnpkyqnmsw4ipey6eotbdnnf/app.bsky.feed.post/3md4khzlybs2f" }, 41 { :post => "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.post/3md5h3jg6as2r" }, 42 { 43 :post => "at://did:plc:4adlzwqtkv4dirxjwq4c3tlm/app.bsky.feed.post/3mcvrvtlk2j2t", 44 :reason => { 45 "$type" => "app.bsky.feed.defs#skeletonReasonRepost", 46 "repost" => "at://did:plc:vmt7o7y6titkqzzxav247zrn/app.bsky.feed.repost/3md54l2q7zc2w" 47 }, 48 :feedContext => "17480484288:28" 49 }, 50 { :post => "at://did:plc:hpv2yni36g2b4ymwsdg2uwre/app.bsky.feed.post/3md4xjrcmj22h" }, 51 { :post => "at://did:plc:2zziubqb5v7bdw2ahteej7wr/app.bsky.feed.post/3md4wfrap6t2c" } 52 ], 53 cursor: "2026-01-24T00:32:27.137Z", 54 reqId: "17480484288" 55 } 56 end 57 58 it 'should not raise an error when cursor or req_id are not set' do 59 response = { 60 posts: [ 61 "at://did:plc:rnpkyqnmsw4ipey6eotbdnnf/app.bsky.feed.post/3md4khzlybs2f", 62 "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.post/3md5h3jg6as2r", 63 "at://did:plc:hpv2yni36g2b4ymwsdg2uwre/app.bsky.feed.post/3md4xjrcmj22h", 64 ] 65 } 66 67 output = subject.generate(response) 68 69 output.should == { 70 feed: [ 71 { :post => "at://did:plc:rnpkyqnmsw4ipey6eotbdnnf/app.bsky.feed.post/3md4khzlybs2f" }, 72 { :post => "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.post/3md5h3jg6as2r" }, 73 { :post => "at://did:plc:hpv2yni36g2b4ymwsdg2uwre/app.bsky.feed.post/3md4xjrcmj22h" }, 74 ] 75 } 76 end 77 78 it 'should raise an error when posts field is missing' do 79 expect { subject.generate({}) }.to raise_error(BlueFactory::InvalidResponseError) 80 end 81 82 it 'should raise an error when posts field is not an array' do 83 response = "at://did:plc:rnpkyqnmsw4ipey6eotbdnnf/app.bsky.feed.post/3md4khzlybs2f" 84 85 expect { subject.generate(posts: response) }.to raise_error(BlueFactory::InvalidResponseError) 86 end 87 88 it 'should convert cursor to a string' do 89 response = { 90 posts: [ 91 "at://did:plc:rnpkyqnmsw4ipey6eotbdnnf/app.bsky.feed.post/3md4khzlybs2f", 92 "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.post/3md5h3jg6as2r", 93 "at://did:plc:hpv2yni36g2b4ymwsdg2uwre/app.bsky.feed.post/3md4xjrcmj22h", 94 ], 95 cursor: 123 96 } 97 98 output = subject.generate(response) 99 100 output[:cursor].should == '123' 101 end 102 103 it 'should convert req_id to a string' do 104 response = { 105 posts: [ 106 "at://did:plc:rnpkyqnmsw4ipey6eotbdnnf/app.bsky.feed.post/3md4khzlybs2f", 107 "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.post/3md5h3jg6as2r", 108 "at://did:plc:hpv2yni36g2b4ymwsdg2uwre/app.bsky.feed.post/3md4xjrcmj22h", 109 ], 110 req_id: 1024 111 } 112 113 output = subject.generate(response) 114 115 output[:reqId].should == '1024' 116 end 117 118 it 'should convert post context to a string' do 119 response = { 120 posts: [ 121 "at://did:plc:rnpkyqnmsw4ipey6eotbdnnf/app.bsky.feed.post/3md4khzlybs2f", 122 { 123 :post => "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.post/3md5h3jg6as2r", 124 :context => 16777216 125 } 126 ] 127 } 128 129 output = subject.generate(response) 130 131 output[:feed][1][:feedContext].should == '16777216' 132 end 133 134 it 'should raise when a post string has an invalid URI' do 135 bad_posts = [ 136 'bad uri', 137 :test, 138 [1, 2, 3], 139 { post: 'bad uri' }, 140 { post: :test }, 141 ] 142 143 bad_posts.each do |post| 144 expect { subject.generate(posts: [post]) }.to raise_error(BlueFactory::InvalidResponseError) 145 end 146 end 147 148 it 'should raise an error when a post hash is missing :post' do 149 response = { 150 posts: [ 151 { reason: { pin: true }} 152 ] 153 } 154 155 expect { subject.generate(response) }.to raise_error(BlueFactory::InvalidResponseError) 156 end 157 158 it 'should raise an error when a post reason is not a hash' do 159 response = { 160 posts: [ 161 { 162 post: "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.post/3md5h3jg6as2r", 163 reason: 'test' 164 } 165 ] 166 } 167 168 expect { subject.generate(response) }.to raise_error(BlueFactory::InvalidResponseError) 169 end 170 171 it 'should raise an error when a post reason is not recognized' do 172 response = { 173 posts: [ 174 { 175 post: "at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.post/3md5h3jg6as2r", 176 reason: { :test => true } 177 } 178 ] 179 } 180 181 expect { subject.generate(response) }.to raise_error(BlueFactory::InvalidResponseError) 182 end 183end