mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at ruby-v 30 kB view raw
1import {RichText} from '@atproto/api' 2 3import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player' 4import { 5 createStarterPackGooglePlayUri, 6 createStarterPackLinkFromAndroidReferrer, 7 parseStarterPackUri, 8} from 'lib/strings/starter-pack' 9import {cleanError} from '../../src/lib/strings/errors' 10import {createFullHandle, makeValidHandle} from '../../src/lib/strings/handles' 11import {enforceLen} from '../../src/lib/strings/helpers' 12import {detectLinkables} from '../../src/lib/strings/rich-text-detection' 13import {shortenLinks} from '../../src/lib/strings/rich-text-manip' 14import { 15 makeRecordUri, 16 toNiceDomain, 17 toShareUrl, 18 toShortUrl, 19} from '../../src/lib/strings/url-helpers' 20 21describe('detectLinkables', () => { 22 const inputs = [ 23 'no linkable', 24 '@start middle end', 25 'start @middle end', 26 'start middle @end', 27 '@start @middle @end', 28 '@full123.test-of-chars', 29 'not@right', 30 '@bad!@#$chars', 31 '@newline1\n@newline2', 32 'parenthetical (@handle)', 33 'start https://middle.com end', 34 'start https://middle.com/foo/bar end', 35 'start https://middle.com/foo/bar?baz=bux end', 36 'start https://middle.com/foo/bar?baz=bux#hash end', 37 'https://start.com/foo/bar?baz=bux#hash middle end', 38 'start middle https://end.com/foo/bar?baz=bux#hash', 39 'https://newline1.com\nhttps://newline2.com', 40 'start middle.com end', 41 'start middle.com/foo/bar end', 42 'start middle.com/foo/bar?baz=bux end', 43 'start middle.com/foo/bar?baz=bux#hash end', 44 'start.com/foo/bar?baz=bux#hash middle end', 45 'start middle end.com/foo/bar?baz=bux#hash', 46 'newline1.com\nnewline2.com', 47 'not.. a..url ..here', 48 'e.g.', 49 'e.g. real.com fake.notreal', 50 'something-cool.jpg', 51 'website.com.jpg', 52 'e.g./foo', 53 'website.com.jpg/foo', 54 'Classic article https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/', 55 'Classic article https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/ ', 56 'https://foo.com https://bar.com/whatever https://baz.com', 57 'punctuation https://foo.com, https://bar.com/whatever; https://baz.com.', 58 'parenthetical (https://foo.com)', 59 'except for https://foo.com/thing_(cool)', 60 ] 61 const outputs = [ 62 ['no linkable'], 63 [{link: '@start'}, ' middle end'], 64 ['start ', {link: '@middle'}, ' end'], 65 ['start middle ', {link: '@end'}], 66 [{link: '@start'}, ' ', {link: '@middle'}, ' ', {link: '@end'}], 67 [{link: '@full123.test-of-chars'}], 68 ['not@right'], 69 [{link: '@bad'}, '!@#$chars'], 70 [{link: '@newline1'}, '\n', {link: '@newline2'}], 71 ['parenthetical (', {link: '@handle'}, ')'], 72 ['start ', {link: 'https://middle.com'}, ' end'], 73 ['start ', {link: 'https://middle.com/foo/bar'}, ' end'], 74 ['start ', {link: 'https://middle.com/foo/bar?baz=bux'}, ' end'], 75 ['start ', {link: 'https://middle.com/foo/bar?baz=bux#hash'}, ' end'], 76 [{link: 'https://start.com/foo/bar?baz=bux#hash'}, ' middle end'], 77 ['start middle ', {link: 'https://end.com/foo/bar?baz=bux#hash'}], 78 [{link: 'https://newline1.com'}, '\n', {link: 'https://newline2.com'}], 79 ['start ', {link: 'middle.com'}, ' end'], 80 ['start ', {link: 'middle.com/foo/bar'}, ' end'], 81 ['start ', {link: 'middle.com/foo/bar?baz=bux'}, ' end'], 82 ['start ', {link: 'middle.com/foo/bar?baz=bux#hash'}, ' end'], 83 [{link: 'start.com/foo/bar?baz=bux#hash'}, ' middle end'], 84 ['start middle ', {link: 'end.com/foo/bar?baz=bux#hash'}], 85 [{link: 'newline1.com'}, '\n', {link: 'newline2.com'}], 86 ['not.. a..url ..here'], 87 ['e.g.'], 88 ['e.g. ', {link: 'real.com'}, ' fake.notreal'], 89 ['something-cool.jpg'], 90 ['website.com.jpg'], 91 ['e.g./foo'], 92 ['website.com.jpg/foo'], 93 [ 94 'Classic article ', 95 { 96 link: 'https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/', 97 }, 98 ], 99 [ 100 'Classic article ', 101 { 102 link: 'https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/', 103 }, 104 ' ', 105 ], 106 [ 107 {link: 'https://foo.com'}, 108 ' ', 109 {link: 'https://bar.com/whatever'}, 110 ' ', 111 {link: 'https://baz.com'}, 112 ], 113 [ 114 'punctuation ', 115 {link: 'https://foo.com'}, 116 ', ', 117 {link: 'https://bar.com/whatever'}, 118 '; ', 119 {link: 'https://baz.com'}, 120 '.', 121 ], 122 ['parenthetical (', {link: 'https://foo.com'}, ')'], 123 ['except for ', {link: 'https://foo.com/thing_(cool)'}], 124 ] 125 it('correctly handles a set of text inputs', () => { 126 for (let i = 0; i < inputs.length; i++) { 127 const input = inputs[i] 128 const output = detectLinkables(input) 129 expect(output).toEqual(outputs[i]) 130 } 131 }) 132}) 133 134describe('makeRecordUri', () => { 135 const inputs: [string, string, string][] = [ 136 ['alice.test', 'app.bsky.feed.post', '3jk7x4irgv52r'], 137 ] 138 const outputs = ['at://alice.test/app.bsky.feed.post/3jk7x4irgv52r'] 139 140 it('correctly builds a record URI', () => { 141 for (let i = 0; i < inputs.length; i++) { 142 const input = inputs[i] 143 const result = makeRecordUri(...input) 144 expect(result).toEqual(outputs[i]) 145 } 146 }) 147}) 148 149describe('makeValidHandle', () => { 150 const inputs = [ 151 'test-handle-123', 152 'test!"#$%&/()=?_', 153 'this-handle-should-be-too-big', 154 ] 155 const outputs = ['test-handle-123', 'test', 'this-handle-should-b'] 156 157 it('correctly parses and corrects handles', () => { 158 for (let i = 0; i < inputs.length; i++) { 159 const result = makeValidHandle(inputs[i]) 160 expect(result).toEqual(outputs[i]) 161 } 162 }) 163}) 164 165describe('createFullHandle', () => { 166 const inputs: [string, string][] = [ 167 ['test-handle-123', 'test'], 168 ['.test.handle', 'test.test.'], 169 ['test.handle.', '.test.test'], 170 ] 171 const outputs = [ 172 'test-handle-123.test', 173 '.test.handle.test.test.', 174 'test.handle.test.test', 175 ] 176 177 it('correctly parses and corrects handles', () => { 178 for (let i = 0; i < inputs.length; i++) { 179 const input = inputs[i] 180 const result = createFullHandle(...input) 181 expect(result).toEqual(outputs[i]) 182 } 183 }) 184}) 185 186describe('enforceLen', () => { 187 const inputs: [string, number][] = [ 188 ['Hello World!', 5], 189 ['Hello World!', 20], 190 ['', 5], 191 ] 192 const outputs = ['Hello', 'Hello World!', ''] 193 194 it('correctly enforces defined length on a given string', () => { 195 for (let i = 0; i < inputs.length; i++) { 196 const input = inputs[i] 197 const result = enforceLen(...input) 198 expect(result).toEqual(outputs[i]) 199 } 200 }) 201}) 202 203describe('cleanError', () => { 204 const inputs = [ 205 'TypeError: Network request failed', 206 'Error: Aborted', 207 'Error: TypeError "x" is not a function', 208 'Error: SyntaxError unexpected token "export"', 209 'Some other error', 210 ] 211 const outputs = [ 212 'Unable to connect. Please check your internet connection and try again.', 213 'Unable to connect. Please check your internet connection and try again.', 214 'TypeError "x" is not a function', 215 'SyntaxError unexpected token "export"', 216 'Some other error', 217 ] 218 219 it('removes extra content from error message', () => { 220 for (let i = 0; i < inputs.length; i++) { 221 const result = cleanError(inputs[i]) 222 expect(result).toEqual(outputs[i]) 223 } 224 }) 225}) 226 227describe('toNiceDomain', () => { 228 const inputs = [ 229 'https://example.com/index.html', 230 'https://bsky.app', 231 'https://bsky.social', 232 '#123123123', 233 ] 234 const outputs = ['example.com', 'bsky.app', 'Bluesky Social', '#123123123'] 235 236 it("displays the url's host in a easily readable manner", () => { 237 for (let i = 0; i < inputs.length; i++) { 238 const result = toNiceDomain(inputs[i]) 239 expect(result).toEqual(outputs[i]) 240 } 241 }) 242}) 243 244describe('toShortUrl', () => { 245 const inputs = [ 246 'https://bsky.app', 247 'https://bsky.app/3jk7x4irgv52r', 248 'https://bsky.app/3jk7x4irgv52r2313y182h9', 249 'https://very-long-domain-name.com/foo', 250 'https://very-long-domain-name.com/foo?bar=baz#andsomemore', 251 ] 252 const outputs = [ 253 'bsky.app', 254 'bsky.app/3jk7x4irgv52r', 255 'bsky.app/3jk7x4irgv52...', 256 'very-long-domain-name.com/foo', 257 'very-long-domain-name.com/foo?bar=baz#...', 258 ] 259 260 it('shortens the url', () => { 261 for (let i = 0; i < inputs.length; i++) { 262 const result = toShortUrl(inputs[i]) 263 expect(result).toEqual(outputs[i]) 264 } 265 }) 266}) 267 268describe('toShareUrl', () => { 269 const inputs = ['https://bsky.app', '/3jk7x4irgv52r', 'item/test/123'] 270 const outputs = [ 271 'https://bsky.app', 272 'https://bsky.app/3jk7x4irgv52r', 273 'https://bsky.app/item/test/123', 274 ] 275 276 it('appends https, when not present', () => { 277 for (let i = 0; i < inputs.length; i++) { 278 const result = toShareUrl(inputs[i]) 279 expect(result).toEqual(outputs[i]) 280 } 281 }) 282}) 283 284describe('shortenLinks', () => { 285 const inputs = [ 286 'start https://middle.com/foo/bar?baz=bux#hash end', 287 'https://start.com/foo/bar?baz=bux#hash middle end', 288 'start middle https://end.com/foo/bar?baz=bux#hash', 289 'https://newline1.com/very/long/url/here\nhttps://newline2.com/very/long/url/here', 290 'Classic article https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/', 291 ] 292 const outputs = [ 293 [ 294 'start middle.com/foo/bar?baz=... end', 295 ['https://middle.com/foo/bar?baz=bux#hash'], 296 ], 297 [ 298 'start.com/foo/bar?baz=... middle end', 299 ['https://start.com/foo/bar?baz=bux#hash'], 300 ], 301 [ 302 'start middle end.com/foo/bar?baz=...', 303 ['https://end.com/foo/bar?baz=bux#hash'], 304 ], 305 [ 306 'newline1.com/very/long/ur...\nnewline2.com/very/long/ur...', 307 [ 308 'https://newline1.com/very/long/url/here', 309 'https://newline2.com/very/long/url/here', 310 ], 311 ], 312 [ 313 'Classic article socket3.wordpress.com/2018/02/03/d...', 314 [ 315 'https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/', 316 ], 317 ], 318 ] 319 320 it('correctly shortens rich text while preserving facet URIs', () => { 321 for (let i = 0; i < inputs.length; i++) { 322 const input = inputs[i] 323 const inputRT = new RichText({text: input}) 324 inputRT.detectFacetsWithoutResolution() 325 const outputRT = shortenLinks(inputRT) 326 expect(outputRT.text).toEqual(outputs[i][0]) 327 expect(outputRT.facets?.length).toEqual(outputs[i][1].length) 328 for (let j = 0; j < outputs[i][1].length; j++) { 329 expect(outputRT.facets![j].features[0].uri).toEqual(outputs[i][1][j]) 330 } 331 } 332 }) 333}) 334 335describe('parseEmbedPlayerFromUrl', () => { 336 const inputs = [ 337 'https://youtu.be/videoId', 338 'https://youtu.be/videoId?t=1s', 339 'https://www.youtube.com/watch?v=videoId', 340 'https://www.youtube.com/watch?v=videoId&feature=share', 341 'https://www.youtube.com/watch?v=videoId&t=1s', 342 'https://youtube.com/watch?v=videoId', 343 'https://youtube.com/watch?v=videoId&feature=share', 344 'https://youtube.com/shorts/videoId', 345 'https://youtube.com/live/videoId', 346 'https://m.youtube.com/watch?v=videoId', 347 'https://music.youtube.com/watch?v=videoId', 348 349 'https://youtube.com/shorts/', 350 'https://youtube.com/', 351 'https://youtube.com/random', 352 'https://youtube.com/live/', 353 354 'https://twitch.tv/channelName', 355 'https://www.twitch.tv/channelName', 356 'https://m.twitch.tv/channelName', 357 358 'https://twitch.tv/channelName/clip/clipId', 359 'https://twitch.tv/videos/videoId', 360 361 'https://open.spotify.com/playlist/playlistId', 362 'https://open.spotify.com/playlist/playlistId?param=value', 363 'https://open.spotify.com/locale/playlist/playlistId', 364 365 'https://open.spotify.com/track/songId', 366 'https://open.spotify.com/track/songId?param=value', 367 'https://open.spotify.com/locale/track/songId', 368 369 'https://open.spotify.com/album/albumId', 370 'https://open.spotify.com/album/albumId?param=value', 371 'https://open.spotify.com/locale/album/albumId', 372 373 'https://soundcloud.com/user/track', 374 'https://soundcloud.com/user/sets/set', 375 'https://soundcloud.com/user/', 376 377 'https://music.apple.com/us/playlist/playlistName/playlistId', 378 'https://music.apple.com/us/album/albumName/albumId', 379 'https://music.apple.com/us/album/albumName/albumId?i=songId', 380 381 'https://vimeo.com/videoId', 382 'https://vimeo.com/videoId?autoplay=0', 383 384 'https://giphy.com/gifs/some-random-gif-name-gifId', 385 'https://giphy.com/gif/some-random-gif-name-gifId', 386 'https://giphy.com/gifs/', 387 388 'https://giphy.com/gifs/39248209509382934029?hh=100&ww=100', 389 390 'https://media.giphy.com/media/gifId/giphy.webp', 391 'https://media0.giphy.com/media/gifId/giphy.webp', 392 'https://media1.giphy.com/media/gifId/giphy.gif', 393 'https://media2.giphy.com/media/gifId/giphy.webp', 394 'https://media3.giphy.com/media/gifId/giphy.mp4', 395 'https://media4.giphy.com/media/gifId/giphy.webp', 396 'https://media5.giphy.com/media/gifId/giphy.mp4', 397 'https://media0.giphy.com/media/gifId/giphy.mp3', 398 'https://media1.google.com/media/gifId/giphy.webp', 399 400 'https://media.giphy.com/media/trackingId/gifId/giphy.webp', 401 402 'https://i.giphy.com/media/gifId/giphy.webp', 403 'https://i.giphy.com/media/gifId/giphy.webp', 404 'https://i.giphy.com/gifId.gif', 405 'https://i.giphy.com/gifId.gif', 406 407 'https://tenor.com/view/gifId', 408 'https://tenor.com/notView/gifId', 409 'https://tenor.com/view', 410 'https://tenor.com/view/gifId.gif', 411 'https://tenor.com/intl/view/gifId.gif', 412 413 'https://media.tenor.com/someID_AAAAC/someName.gif?hh=100&ww=100', 414 'https://media.tenor.com/someID_AAAAC/someName.gif', 415 'https://media.tenor.com/someID/someName.gif', 416 'https://media.tenor.com/someID', 417 'https://media.tenor.com', 418 419 'https://www.flickr.com/photos/username/albums/72177720308493661', 420 'https://flickr.com/photos/username/albums/72177720308493661', 421 'https://flickr.com/photos/username/albums/72177720308493661/', 422 'https://flickr.com/photos/username/albums/72177720308493661//', 423 'https://flic.kr/s/aHBqjAES3i', 424 425 'https://flickr.com/foetoes/username/albums/3903', 426 'https://flickr.com/albums/3903', 427 'https://flic.kr/s/OolI', 428 'https://flic.kr/t/aHBqjAES3i', 429 430 'https://www.flickr.com/groups/898944@N23/pool', 431 'https://flickr.com/groups/898944@N23/pool', 432 'https://flickr.com/groups/898944@N23/pool/', 433 'https://flickr.com/groups/898944@N23/pool//', 434 'https://flic.kr/go/8WJtR', 435 436 'https://www.flickr.com/groups/898944@N23/', 437 'https://www.flickr.com/groups', 438 ] 439 440 const outputs = [ 441 { 442 type: 'youtube_video', 443 source: 'youtube', 444 playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=0', 445 }, 446 { 447 type: 'youtube_video', 448 source: 'youtube', 449 playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=1', 450 }, 451 { 452 type: 'youtube_video', 453 source: 'youtube', 454 playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=0', 455 }, 456 { 457 type: 'youtube_video', 458 source: 'youtube', 459 playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=0', 460 }, 461 { 462 type: 'youtube_video', 463 source: 'youtube', 464 playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=1', 465 }, 466 { 467 type: 'youtube_video', 468 source: 'youtube', 469 playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=0', 470 }, 471 { 472 type: 'youtube_video', 473 source: 'youtube', 474 playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=0', 475 }, 476 { 477 type: 'youtube_short', 478 source: 'youtubeShorts', 479 hideDetails: true, 480 playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=0', 481 }, 482 { 483 type: 'youtube_video', 484 source: 'youtube', 485 playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=0', 486 }, 487 { 488 type: 'youtube_video', 489 source: 'youtube', 490 playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=0', 491 }, 492 { 493 type: 'youtube_video', 494 source: 'youtube', 495 playerUri: 'https://bsky.app/iframe/youtube.html?videoId=videoId&start=0', 496 }, 497 498 undefined, 499 undefined, 500 undefined, 501 undefined, 502 503 { 504 type: 'twitch_video', 505 source: 'twitch', 506 playerUri: `https://player.twitch.tv/?volume=0.5&!muted&autoplay&channel=channelName&parent=localhost`, 507 }, 508 { 509 type: 'twitch_video', 510 source: 'twitch', 511 playerUri: `https://player.twitch.tv/?volume=0.5&!muted&autoplay&channel=channelName&parent=localhost`, 512 }, 513 { 514 type: 'twitch_video', 515 source: 'twitch', 516 playerUri: `https://player.twitch.tv/?volume=0.5&!muted&autoplay&channel=channelName&parent=localhost`, 517 }, 518 { 519 type: 'twitch_video', 520 source: 'twitch', 521 playerUri: `https://clips.twitch.tv/embed?volume=0.5&autoplay=true&clip=clipId&parent=localhost`, 522 }, 523 { 524 type: 'twitch_video', 525 source: 'twitch', 526 playerUri: `https://player.twitch.tv/?volume=0.5&!muted&autoplay&video=videoId&parent=localhost`, 527 }, 528 529 { 530 type: 'spotify_playlist', 531 source: 'spotify', 532 playerUri: `https://open.spotify.com/embed/playlist/playlistId`, 533 }, 534 { 535 type: 'spotify_playlist', 536 source: 'spotify', 537 playerUri: `https://open.spotify.com/embed/playlist/playlistId`, 538 }, 539 { 540 type: 'spotify_playlist', 541 source: 'spotify', 542 playerUri: `https://open.spotify.com/embed/playlist/playlistId`, 543 }, 544 545 { 546 type: 'spotify_song', 547 source: 'spotify', 548 playerUri: `https://open.spotify.com/embed/track/songId`, 549 }, 550 { 551 type: 'spotify_song', 552 source: 'spotify', 553 playerUri: `https://open.spotify.com/embed/track/songId`, 554 }, 555 { 556 type: 'spotify_song', 557 source: 'spotify', 558 playerUri: `https://open.spotify.com/embed/track/songId`, 559 }, 560 561 { 562 type: 'spotify_album', 563 source: 'spotify', 564 playerUri: `https://open.spotify.com/embed/album/albumId`, 565 }, 566 { 567 type: 'spotify_album', 568 source: 'spotify', 569 playerUri: `https://open.spotify.com/embed/album/albumId`, 570 }, 571 { 572 type: 'spotify_album', 573 source: 'spotify', 574 playerUri: `https://open.spotify.com/embed/album/albumId`, 575 }, 576 577 { 578 type: 'soundcloud_track', 579 source: 'soundcloud', 580 playerUri: `https://w.soundcloud.com/player/?url=https://soundcloud.com/user/track&auto_play=true&visual=false&hide_related=true`, 581 }, 582 { 583 type: 'soundcloud_set', 584 source: 'soundcloud', 585 playerUri: `https://w.soundcloud.com/player/?url=https://soundcloud.com/user/sets/set&auto_play=true&visual=false&hide_related=true`, 586 }, 587 undefined, 588 589 { 590 type: 'apple_music_playlist', 591 source: 'appleMusic', 592 playerUri: 593 'https://embed.music.apple.com/us/playlist/playlistName/playlistId', 594 }, 595 { 596 type: 'apple_music_album', 597 source: 'appleMusic', 598 playerUri: 'https://embed.music.apple.com/us/album/albumName/albumId', 599 }, 600 { 601 type: 'apple_music_song', 602 source: 'appleMusic', 603 playerUri: 604 'https://embed.music.apple.com/us/album/albumName/albumId?i=songId', 605 }, 606 607 { 608 type: 'vimeo_video', 609 source: 'vimeo', 610 playerUri: 'https://player.vimeo.com/video/videoId?autoplay=1', 611 }, 612 { 613 type: 'vimeo_video', 614 source: 'vimeo', 615 playerUri: 'https://player.vimeo.com/video/videoId?autoplay=1', 616 }, 617 618 { 619 type: 'giphy_gif', 620 source: 'giphy', 621 isGif: true, 622 hideDetails: true, 623 metaUri: 'https://giphy.com/gifs/gifId', 624 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 625 }, 626 undefined, 627 undefined, 628 { 629 type: 'giphy_gif', 630 source: 'giphy', 631 isGif: true, 632 hideDetails: true, 633 metaUri: 'https://giphy.com/gifs/39248209509382934029', 634 playerUri: 'https://i.giphy.com/media/39248209509382934029/200.webp', 635 }, 636 { 637 type: 'giphy_gif', 638 source: 'giphy', 639 isGif: true, 640 hideDetails: true, 641 metaUri: 'https://giphy.com/gifs/gifId', 642 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 643 }, 644 { 645 type: 'giphy_gif', 646 source: 'giphy', 647 isGif: true, 648 hideDetails: true, 649 metaUri: 'https://giphy.com/gifs/gifId', 650 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 651 }, 652 { 653 type: 'giphy_gif', 654 source: 'giphy', 655 isGif: true, 656 hideDetails: true, 657 metaUri: 'https://giphy.com/gifs/gifId', 658 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 659 }, 660 { 661 type: 'giphy_gif', 662 source: 'giphy', 663 isGif: true, 664 hideDetails: true, 665 metaUri: 'https://giphy.com/gifs/gifId', 666 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 667 }, 668 { 669 type: 'giphy_gif', 670 source: 'giphy', 671 isGif: true, 672 hideDetails: true, 673 metaUri: 'https://giphy.com/gifs/gifId', 674 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 675 }, 676 { 677 type: 'giphy_gif', 678 source: 'giphy', 679 isGif: true, 680 hideDetails: true, 681 metaUri: 'https://giphy.com/gifs/gifId', 682 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 683 }, 684 undefined, 685 undefined, 686 undefined, 687 688 { 689 type: 'giphy_gif', 690 source: 'giphy', 691 isGif: true, 692 hideDetails: true, 693 metaUri: 'https://giphy.com/gifs/gifId', 694 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 695 }, 696 697 { 698 type: 'giphy_gif', 699 source: 'giphy', 700 isGif: true, 701 hideDetails: true, 702 metaUri: 'https://giphy.com/gifs/gifId', 703 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 704 }, 705 { 706 type: 'giphy_gif', 707 source: 'giphy', 708 isGif: true, 709 hideDetails: true, 710 metaUri: 'https://giphy.com/gifs/gifId', 711 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 712 }, 713 { 714 type: 'giphy_gif', 715 source: 'giphy', 716 isGif: true, 717 hideDetails: true, 718 metaUri: 'https://giphy.com/gifs/gifId', 719 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 720 }, 721 { 722 type: 'giphy_gif', 723 source: 'giphy', 724 isGif: true, 725 hideDetails: true, 726 metaUri: 'https://giphy.com/gifs/gifId', 727 playerUri: 'https://i.giphy.com/media/gifId/200.webp', 728 }, 729 730 undefined, 731 undefined, 732 undefined, 733 undefined, 734 undefined, 735 736 { 737 type: 'tenor_gif', 738 source: 'tenor', 739 isGif: true, 740 hideDetails: true, 741 playerUri: 'https://t.gifs.bsky.app/someID_AAAAM/someName.gif', 742 dimensions: { 743 width: 100, 744 height: 100, 745 }, 746 }, 747 undefined, 748 undefined, 749 undefined, 750 undefined, 751 752 { 753 type: 'flickr_album', 754 source: 'flickr', 755 playerUri: 'https://embedr.flickr.com/photosets/72177720308493661', 756 }, 757 { 758 type: 'flickr_album', 759 source: 'flickr', 760 playerUri: 'https://embedr.flickr.com/photosets/72177720308493661', 761 }, 762 { 763 type: 'flickr_album', 764 source: 'flickr', 765 playerUri: 'https://embedr.flickr.com/photosets/72177720308493661', 766 }, 767 { 768 type: 'flickr_album', 769 source: 'flickr', 770 playerUri: 'https://embedr.flickr.com/photosets/72177720308493661', 771 }, 772 { 773 type: 'flickr_album', 774 source: 'flickr', 775 playerUri: 'https://embedr.flickr.com/photosets/72177720308493661', 776 }, 777 778 undefined, 779 undefined, 780 undefined, 781 undefined, 782 783 { 784 type: 'flickr_album', 785 source: 'flickr', 786 playerUri: 'https://embedr.flickr.com/groups/898944@N23', 787 }, 788 { 789 type: 'flickr_album', 790 source: 'flickr', 791 playerUri: 'https://embedr.flickr.com/groups/898944@N23', 792 }, 793 { 794 type: 'flickr_album', 795 source: 'flickr', 796 playerUri: 'https://embedr.flickr.com/groups/898944@N23', 797 }, 798 { 799 type: 'flickr_album', 800 source: 'flickr', 801 playerUri: 'https://embedr.flickr.com/groups/898944@N23', 802 }, 803 { 804 type: 'flickr_album', 805 source: 'flickr', 806 playerUri: 'https://embedr.flickr.com/groups/898944@N23', 807 }, 808 809 undefined, 810 undefined, 811 ] 812 813 it('correctly grabs the correct id from uri', () => { 814 for (let i = 0; i < inputs.length; i++) { 815 const input = inputs[i] 816 const output = outputs[i] 817 818 const res = parseEmbedPlayerFromUrl(input) 819 820 expect(res).toEqual(output) 821 } 822 }) 823}) 824 825describe('createStarterPackLinkFromAndroidReferrer', () => { 826 const validOutput = 'at://haileyok.com/app.bsky.graph.starterpack/rkey' 827 828 it('returns a link when input contains utm_source and utm_content', () => { 829 expect( 830 createStarterPackLinkFromAndroidReferrer( 831 'utm_source=bluesky&utm_content=starterpack_haileyok.com_rkey', 832 ), 833 ).toEqual(validOutput) 834 835 expect( 836 createStarterPackLinkFromAndroidReferrer( 837 'utm_source=bluesky&utm_content=starterpack_test-lover-9000.com_rkey', 838 ), 839 ).toEqual('at://test-lover-9000.com/app.bsky.graph.starterpack/rkey') 840 }) 841 842 it('returns a link when input contains utm_source and utm_content in different order', () => { 843 expect( 844 createStarterPackLinkFromAndroidReferrer( 845 'utm_content=starterpack_haileyok.com_rkey&utm_source=bluesky', 846 ), 847 ).toEqual(validOutput) 848 }) 849 850 it('returns a link when input contains other parameters as well', () => { 851 expect( 852 createStarterPackLinkFromAndroidReferrer( 853 'utm_source=bluesky&utm_medium=starterpack&utm_content=starterpack_haileyok.com_rkey', 854 ), 855 ).toEqual(validOutput) 856 }) 857 858 it('returns null when utm_source is not present', () => { 859 expect( 860 createStarterPackLinkFromAndroidReferrer( 861 'utm_content=starterpack_haileyok.com_rkey', 862 ), 863 ).toEqual(null) 864 }) 865 866 it('returns null when utm_content is not present', () => { 867 expect( 868 createStarterPackLinkFromAndroidReferrer('utm_source=bluesky'), 869 ).toEqual(null) 870 }) 871 872 it('returns null when utm_content is malformed', () => { 873 expect( 874 createStarterPackLinkFromAndroidReferrer( 875 'utm_content=starterpack_haileyok.com', 876 ), 877 ).toEqual(null) 878 879 expect( 880 createStarterPackLinkFromAndroidReferrer('utm_content=starterpack'), 881 ).toEqual(null) 882 883 expect( 884 createStarterPackLinkFromAndroidReferrer( 885 'utm_content=starterpack_haileyok.com_rkey_more', 886 ), 887 ).toEqual(null) 888 889 expect( 890 createStarterPackLinkFromAndroidReferrer( 891 'utm_content=notastarterpack_haileyok.com_rkey', 892 ), 893 ).toEqual(null) 894 }) 895}) 896 897describe('parseStarterPackHttpUri', () => { 898 const baseUri = 'https://bsky.app/start' 899 900 it('returns a valid at uri when http uri is valid', () => { 901 const validHttpUri = `${baseUri}/haileyok.com/rkey` 902 expect(parseStarterPackUri(validHttpUri)).toEqual({ 903 name: 'haileyok.com', 904 rkey: 'rkey', 905 }) 906 907 const validHttpUri2 = `${baseUri}/haileyok.com/ilovetesting` 908 expect(parseStarterPackUri(validHttpUri2)).toEqual({ 909 name: 'haileyok.com', 910 rkey: 'ilovetesting', 911 }) 912 913 const validHttpUri3 = `${baseUri}/testlover9000.com/rkey` 914 expect(parseStarterPackUri(validHttpUri3)).toEqual({ 915 name: 'testlover9000.com', 916 rkey: 'rkey', 917 }) 918 }) 919 920 it('returns null when there is no rkey', () => { 921 const validHttpUri = `${baseUri}/haileyok.com` 922 expect(parseStarterPackUri(validHttpUri)).toEqual(null) 923 }) 924 925 it('returns null when there is an extra path', () => { 926 const validHttpUri = `${baseUri}/haileyok.com/rkey/other` 927 expect(parseStarterPackUri(validHttpUri)).toEqual(null) 928 }) 929 930 it('returns null when there is no handle or rkey', () => { 931 const validHttpUri = `${baseUri}` 932 expect(parseStarterPackUri(validHttpUri)).toEqual(null) 933 }) 934 935 it('returns null when the route is not /start or /starter-pack', () => { 936 const validHttpUri = 'https://bsky.app/start/haileyok.com/rkey' 937 expect(parseStarterPackUri(validHttpUri)).toEqual({ 938 name: 'haileyok.com', 939 rkey: 'rkey', 940 }) 941 942 const validHttpUri2 = 'https://bsky.app/starter-pack/haileyok.com/rkey' 943 expect(parseStarterPackUri(validHttpUri2)).toEqual({ 944 name: 'haileyok.com', 945 rkey: 'rkey', 946 }) 947 948 const invalidHttpUri = 'https://bsky.app/profile/haileyok.com/rkey' 949 expect(parseStarterPackUri(invalidHttpUri)).toEqual(null) 950 }) 951 952 it('returns the at uri when the input is a valid starterpack at uri', () => { 953 const validAtUri = 'at://did:123/app.bsky.graph.starterpack/rkey' 954 expect(parseStarterPackUri(validAtUri)).toEqual({ 955 name: 'did:123', 956 rkey: 'rkey', 957 }) 958 }) 959 960 it('returns null when the at uri has no rkey', () => { 961 const validAtUri = 'at://did:123/app.bsky.graph.starterpack' 962 expect(parseStarterPackUri(validAtUri)).toEqual(null) 963 }) 964 965 it('returns null when the collection is not app.bsky.graph.starterpack', () => { 966 const validAtUri = 'at://did:123/app.bsky.graph.list/rkey' 967 expect(parseStarterPackUri(validAtUri)).toEqual(null) 968 }) 969 970 it('returns null when the input is undefined', () => { 971 expect(parseStarterPackUri(undefined)).toEqual(null) 972 }) 973}) 974 975describe('createStarterPackGooglePlayUri', () => { 976 const base = 977 'https://play.google.com/store/apps/details?id=xyz.blueskyweb.app&referrer=utm_source%3Dbluesky%26utm_medium%3Dstarterpack%26utm_content%3Dstarterpack_' 978 979 it('returns valid google play uri when input is valid', () => { 980 expect(createStarterPackGooglePlayUri('name', 'rkey')).toEqual( 981 `${base}name_rkey`, 982 ) 983 }) 984 985 it('returns null when no rkey is supplied', () => { 986 // @ts-expect-error test 987 expect(createStarterPackGooglePlayUri('name', undefined)).toEqual(null) 988 }) 989 990 it('returns null when no name or rkey are supplied', () => { 991 // @ts-expect-error test 992 expect(createStarterPackGooglePlayUri(undefined, undefined)).toEqual(null) 993 }) 994 995 it('returns null when rkey is supplied but no name', () => { 996 // @ts-expect-error test 997 expect(createStarterPackGooglePlayUri(undefined, 'rkey')).toEqual(null) 998 }) 999})